Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

[XS] C printf() and Microsoft compilers.

by syphilis (Archbishop)
on Dec 18, 2019 at 03:15 UTC ( [id://11110314]=perlquestion: print w/replies, xml ) Need Help??

syphilis has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I have an issue with the Microsoft compiler (cl) toolchain, in relation only to those perls whose $Config{ivsize} and $Config{nvsize} are both 8.
Note that such a perl configuration is very common.
The demo:
use strict; use Config; use Devel::Peek; die "This configuration of perl not relevant to the issue" unless $Config{nvsize} == $Config{ivsize}; use Inline C => Config => PRE_HEAD => "#ifndef __USE_MINGW_ANSI_STDIO\n#define __USE_MINGW_ANS +I_STDIO 1\n#endif\n", ; use Inline C => <<'EOC'; void foo(SV * in) { printf("%.20" NVgf, SvNV(in)); printf("\n"); } EOC # Create an NV whose value is # 18446744073709549568 my $nv = ((1 << 53) - 1) / 2 * 4096; # Dump $nv; # Shows that it's an NV. foo($nv); foo(18446744073709549568);
The desired output (which I see on Linux and mingw-built windows perls) is:
18446744073709549568 18446744073709549568
My only perl built using a Microsoft compiler (5.16.0 using cl 14.00.40310.41) doesn't play ball, and outputs:
18446744073709550000 18446744073709550000
How do I get the output I want with this cl-built perl ?
Do more modern versions of the MS toolchain enable me to get my desired output ?

Any solution that involves changing the final argument that printf() takes (ie SvNV(in)) is probably not a satisfactory one.
But if there's some symbol that can be defined, or some alteration to the formatting spec, then that would be great.

BTW, the script only works as desired with mingw-built perls because it defines __USE_MINGW_ANSI_STDIO to a true value if perl has not already defined it.
Without that definition, mingw-built perls display the same output as my cl-built perl-5.16.0.
I believe the problem with the cl-built perl is a toolchain issue, not a perl one.

Cheers,
Rob

Replies are listed 'Best First'.
Re: [XS] C printf() and Microsoft compilers.
by jcb (Parson) on Dec 19, 2019 at 00:34 UTC

    This sounds to me like an issue between a standards-conforming stdio (which you get with MinGW by defining __USE_MINGW_ANSI_STDIO) and the Microsoft stdio.

    MinGW mostly use the Microsoft runtime libraries, and that preprocessor symbol presumably selects overriding the system's stdio with another implementation that actually conforms to the relevant standards. Blame Microsoft, for it is their library that is misbehaving.

Re: [XS] C printf() and Microsoft compilers.
by NERDVANA (Deacon) on Dec 20, 2019 at 06:01 UTC
    You picked a value for the $nv which exceeds the number of digits of precision for a 64-bit float (approx 16 decimal digits). The output of MS's libc printf function is not unreasonable because it essentially gives you all 16 digits of precision correctly and then pads the rest with zeroes. It might actually be considered helpful for scientific applications because it correctly displays the digits of precision that you really have. In other words, the ``49568`` at the end of the number is not actually a stored value, it is an artifact of the base-2 encoding and gcc's printf code.
      The output of MS's libc printf function is not unreasonable because it essentially gives you all 16 digits of precision correctly and then pads the rest with zeroes.

      I pretty much agree with that assessment - though I believe it's actually rounding to 17 digits, not 16. (16 digits is not enough.)
      However, it's a pity that MS doesn't provide the service offered by gcc.
      I was hoping that someone would tell me that with MS toolchains there was a means of extracting the same behaviour, if only with toolchains beyond a certain version.
      But, if that's not the case, then so be it.

      It might actually be considered helpful for scientific applications because it correctly displays the digits of precision that you really have

      I suppose that's how one would go about trying to present the behaviour as being desirable.
      But, given that the value is a 53-bit integer (that doesn't exceed double precision), multiplied by a power of 2 (that doesn't exceed the maximum double exponent),
      I see no harm in displaying the exact value of the double - as opposed to displaying a 17-digit value padded with sufficient zeroes that rounds to the same double.

      To me, it's not a question of "right" and "wrong" - rather a question of "helpful" and "pointless".

      The extreme case is that gcc provides:
      C:\>perl -MPOSIX -e "printf '%.0f', POSIX::DBL_MAX;" 1797693134862315708145274237317043567980705675258449965989174768031572 +607800285387605895586327668781715404589535143824642343213268894641827 +684675467035375169860499105765512820762454900903893289440758685084551 +339423045832369032229481658085593321233482747978262041447231687381771 +80919299881250404026184124858368
      whereas cl provides:
      C:\Windows\System32>perl -MPOSIX -e "printf '%.0f', POSIX::DBL_MAX;" 1797693134862315700000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000
      Both values assign to the same double, but the former is an exact representation of that double, whereas the latter is an approximation.

      Cheers,
      Rob

        In a scientific application, that exact floating point representation could be the literal you gave it, but it could also be the result of math that has been rounded to fit in the 53 bit mantissa. For example perl -MPOSIX -e “printf ‘%.0f’, POSIX::DBL_MAX - 10000000000000000;” Now the very precise answer from gcc is wrong. If you actually care about the digits beyond the first 17 then you need to use a BigFloat.

        Anyway, but no I don’t know if there’s a way to ask ms libc for a different implementation.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11110314]
Approved by GrandFather
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (6)
As of 2024-04-18 19:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found