in reply to Re: porting C code to Perl
in thread porting C code to Perl

Hi Monk::Thomas,

The predigit value may set to 0 magically with some C compilers, I'm not sure. It's not the case on the Mac.

predigit, nines = 0;

I changed the line to this.

predigit = 0, nines = 0;

Basing on Discipulus's example, I too am interested and will try a plain Perl version. Then, will try parallelization via a number sequence for j. Thank you for the fun, fellow monks.

Regards, Mario

Replies are listed 'Best First'.
Re^3: porting C code to Perl
by Monk::Thomas (Friar) on Oct 24, 2017 at 11:43 UTC
    The predigit value may set to 0 magically with some C compilers

    Since this value is defined as a global variable (not inside a function) and is an integral data type (not part of an object/struct) it is safe to assume 'predigit' is initialized as zero by the compiler. I guess the author of the C code wasn't sure and tried to initialize both variables (just in case) ... and got it wrong. However it doesn't matter, because the '= 0' doesn't actually add anything.

    test #1 - define at global scope

    #include <stdio.h> int value1, value2 = 9; void main(void) { printf("%d %d\n", value1, value2); }
    prints '0 9', not 9 9

    test #2 - define in function

    #include <stdio.h> void func(void) { int value1, value2 = 9; printf("%d %d\n", value1, value2); } void main(void) { func(); }
    may print '996873600 9' or '-1944996480 9' or '-51174016 9'

      However it doesn't matter, because the '= 0' doesn't actually add anything.

      From testing, it seems to matter on the Mac platform including CentOS 7.3. I compared the output with this site. No warnings are emitted on CentOS 7.3.

      Without '= 0'

      predigit, nines = 0; -- Mac OS X, Apple LLVM version 7.3.0 (clang-703.0.31) demo.c:41:13: warning: expression result unused [-Wunused-value] predigit, nines = 0; ^~~~~~~~ 1 warning generated. 0314159265358979323846264338327954288419716939937510582097494459230781 +6406286208998628734825342117067 | + | 4 + 7 -- Linux, gcc version 4.8.5 20150623 0314159265358979323846264338327954288419716939937510582097494459230781 +6406286208998628734825342117067 | + | 4 + 7

      With '= 0'

      predigit = 0, nines = 0; 0314159265358979323846264338327950288419716939937510582097494459230781 +6406286208998628034825342117067 | + | 0 + 0
        Sorry, for some reason I believed
        int nines = 0; int predigit = 0;
        to read
        int nines, predigit = 0;

        instead and this was what I was talking about (and showcasing in the tests). In this situation '= 0' adds nothing.

        For 'predigit, nines = 0;': You are totally correct - it does make a difference. I assume this is a bug in the original code which has not been spotted when verifying the result using the widely deployed Eyeball Mark 1 test suite.

        Edit: There are two different things being talked about and I'm replying to different than Mario was discussing. Apologies -- too many threads and too many versions of code being discussed for me to keep track. The message below discusses the initialization of globals, as some versions of the Rabinowitz/Wagon code just use globals for the variables and the understanding that the C spec means they get initialized to 0. This was what I interpreted "The predigit value may set to 0 magically with some C compilers" to be referencing. The stackoverflow code does initialize them, but Mario points out that the line "predigit, nine=0" in the middle of the loop is basically the same in this case as "predigit; nine = 0" which sets nine to zero and that's it. On this line indeed no proper compiler would modify predigit. That's clearly a confusing statement that makes it unclear what was intended. See the original 1995 article for the Pascal code that looks suspiciously similar, and indeed it was supposed to set predigit to 0. Arndt and Haendel's book on page 82 points out this implementation has some bugs and they give correct C code. But all of this is tangential to initialization in this particular code. since it clearly initializes predigit and nines at the top.

        That's strange. It doesn't do that on my Mac or RH Linux system. Any compiler that does would seem to be broken, as Monk::Thomas points out.

        If this was done inside a function such as main, then it is uninitialized and may or may not be zero depending on the whim of the compiler, but it rightly warns you that you're doing it wrong. The fact that you're getting that warning means your example probably doesn't have that line at file scope (e.g. a global).

        That said, one thing I've learned is that maintenance and readibility are important. Principle of least surprise, etc. I would really want to see the variables (1) local to the function, and (2) initialized. If there is some reason they have to be globals, either initialize them explicitly so every reader can clearly see it, or write a comment explaining it. I suppose if you're working deep in Bell Labs in the 70s or Berkeley in the 80s then maybe you could be excused for having a much better opinion of your co-workers and future self. But not now. Witness this whole subthread :). Besides, a nice self-contained function that takes an argument for number of digits seems much more professional. Otherwise you're just making one-off maintenance-hell scripts even though it's C.

        In the original posting's link, the next answer has a version of the Winter/Flammenkamp implementation (without overflow correction). It still uses globals (boo) but at least initializes some, and even includes comments. Hilariously even with all of that, it still relies on d being set to 0 because it is a global.

        re the multiple variables on a line with / without initialization, I've started doing more of that. Trying to save previous newlines I suppose :/ I still find I dislike the "b=c-=14" sort of construct used here, but it bothers me less now than it did 5 years ago.

      it is safe to assume 'predigit' is initialized as zero by the compiler

      One should be careful with this assumption, I've seen several C compilers for microcontrollers that don't do this by default, in order to save on instruction memory (which can matter on tiny uC's).

        So you're saying that this code:

        #include <stdio.h> int value; void main(void) { printf("%d\n", value); }

        may output something else then 0 on these platforms/compilers? Looking at ANSI C (as the smallest common base) I would say these compilers are in violation of the C Standard and cannot be truly called C. (But I may be wrong - I'm not a greybearded C guru.)

        From the C89 standard, section 3.5.7

        If an object that has static storage duration is not initialized explicitly, it is initialized implicitly as if every member that has arithmetic type were assigned 0 and every member that has pointer type were assigned a null pointer constant.

        (I am deliberately quoting C89 and not a more recent standard too make sure this isn't a later addition / clarification.)