32/64 bit cc differences

Discussion in 'C Programming' started by JohnF, Jan 10, 2014.

  1. Then it's only *mostly* portable; the standard allows int to be as
    narrow as 16 bits. If you don't mind that restriction, that's fine (I'd
    probably add a compile time assertion that int is at least 32 bits) --
    or you might consider using int32_t and uint32_t when you need a 32-bit
    type. Or intleast32_t or intfast32_t if you need *at least* 32
    bits.
    I'd probably use int64_t and friends. But what warnings do you get when
    you use long long? You can likely get rid of any such warnings by
    telling your compiler to conform to C99 or later.
     
    Keith Thompson, Jan 11, 2014
    #61
    1. Advertisements

  2. JohnF

    James Kuyper Guest

    In C99, several features were added that addressed rounding:
    the macro FLT_ROUNDS was added to <float.h>; it expands to an expression
    that will indicate the current rounding mode.

    "A floating expression may be contracted, that is, evaluated as though
    it were a single operation, thereby omitting rounding errors implied by
    the source code and the expression evaluation method.89) The FP_CONTRACT
    pragma in <math.h> provides a way to disallow contracted expressions."
    (6.5p8)

    fegetround() gets the current rounding direction, fesetround() sets it.
    The possible rounding directions are identified by macros #defined in
    <fenv.h>. They are all optional: #ifndef, the corresponding rounding
    direction is not supported.

    Several new functions were added to <math.h> for rounding to an integer
    in various ways: nearbyint(), lrint(), round().

    C is a little stricter than that: Conversions to floating point type are
    required to result in the nearest higher or nearest lower representable
    value (6.3.1.4, 6.3.1.5), so (double)196 is not allowed to have a value
    of 42.0. Also, "For decimal floating constants, and also for hexadecimal
    floating constants when FLT_RADIX is not a power of 2, the result is
    either the nearest representable value, or the larger or smaller
    representable value immediately adjacent to the nearest representable
    value, chosen in an implementation-defined manner.
    For hexadecimal floating constants when FLT_RADIX is a power of 2, the
    result is correctly rounded." (6.4.4.2p3), so the floating point
    expression 3.0 is not allowed to have a value of 42.0. Also, all
    floating point comparison operators (<, >, <=, >=, ==, !=) are required
    to return either 0 or 1, and they must return the correct value - they
    are not allowed to perform fuzzy comparisons.

    However, unless an implementation of C chooses to pre-#define
    __STDC_IEC_559__, in all other regards C is not very strict at all: "The
    accuracy of the floating-point operations (+, -, *, /) and of the
    library functions in <math.h> and <complex.h> that return floating-point
    results is implementation defined, as is the accuracy of the conversion
    between floating-point internal representations and string
    representations performed by the library functions in <stdio.h>,
    <stdlib.h>, and <wchar.h>. The implementation may state that the
    accuracy is unknown."

    Therefore, a conforming implementation of C is allowed to evaluate the
    division in DBL_MIN/DBL_MAX < DBL_MAX with such lousy accuracy that the
    comparison ends up being false.

    If __STDC_IEC_559__ is pre-#defined, the implementation must conform to
    the requirements of Annex K, which is based upon, but not identical
    with, IEC 60559 (which in turn, is essentially equivalent to IEEE 754).
    In that case, the floating point accuracy requirements are quite strict
    - they come pretty close to being as strict as it is practically
    possible for them to be. Which is still to low a requirement for this
    kind of use.
     
    James Kuyper, Jan 12, 2014
    #62
    1. Advertisements

  3. JohnF

    JohnF Guest

    It's no problem. I meant "obnoxious" humorously.
    In fact, I'd rather continue seeing the warnings -- reminds me
    I'm doing something a little funky that probably ought to be changed.
     
    JohnF, Jan 12, 2014
    #63
  4. JohnF

    JohnF Guest

    Yeah, but that's pretty much deprecated/archaic, at least for
    general purpose computers. I usually just try to follow K&R 2nd ed
    for "portable" syntax, whereas "portable semantics" gets trickier,
    and I usually just try to figure "anything that can go wrong will".


    That might be preferable to LL. All three compilers
    64-bit: cc --version cc (Debian 4.3.2-1.1) 4.3.2
    32-bit: cc --version cc (NetBSD nb2 20110806) 4.5.3
    cc --version cc (GCC) 4.7.1
    issue similar -pedantic -Wall warnings. Explicitly, from 4.7.1,
    fm.c: In function 'rseeder':
    fm.c:865:6: warning: ISO C90 does not support 'long long' [-Wlong-long]
    fm.c:866:11: warning: use of C99 long long integer constant [-Wlong-long]
    fm.c:877:20: warning: ISO C90 does not support 'long long' [-Wlong-long]
    fm.c:878:11: warning: ISO C90 does not support 'long long' [-Wlong-long]
    fm.c:880:25: warning: use of C99 long long integer constant [-Wlong-long]
    fm.c:880:30: warning: use of C99 long long integer constant [-Wlong-long]
    fm.c:880:37: warning: use of C99 long long integer constant [-Wlong-long]
    fm.c:892:3: warning: ISO C90 does not support the 'll' gnu_printf
    length modifier [-Wformat]
    But that whole function ought to be re-algorithmized anyway,
    so my concern is pretty minimal.
     
    JohnF, Jan 12, 2014
    #64
  5. JohnF

    JohnF Guest

    I think you're right that I mistakenly said "round" once or twice,
    where I really should have said "truncate". Rounding isn't actually
    an issue. The code is using a (random) float 0.0<=f<1.0 to calculate
    an int ilo<=i<=ihi, with more-or-less the usual kind of formula
    i = ilo + f*(ihi-ilo+1); better written as
    i = ilo + (int)(f*(float)(ihi-ilo+1));
    So I want it to truncate.
     
    JohnF, Jan 12, 2014
    #65
  6. JohnF

    JohnF Guest

    Yes, Park&Miller, according to the discussion in Numerical Recipes
    in C, 2nd ed, page 280, from which I copied the code.
    Thanks, guys. I was just getting around to thinking about
    the best way to handle this. Glad I read your discussion first.
     
    JohnF, Jan 12, 2014
    #66
  7. JohnF

    JohnF Guest

    Answer's hiding in
    http://www.forkosh.com/fm.html?algorithms.permutebits
    (use the ?, not a #),
    "With default block sizes randomly selected between
    2048 and 8192 bytes, and with default noise between
    32 and 256 bytes per block, fm's permutations range
    between 16640 and 67584 bits."
     
    JohnF, Jan 12, 2014
    #67
  8. JohnF

    JohnF Guest

    Yeah, that's been the suggestion, which I'll definitely be taking.
    Eric's preceding followup seems to contain the definitive discussion
    about how to best do this.
    Not sure myself. See Numerical Recipes in C, 2nd ed, page 280
    for discussion of theory and algorithm.
    I copied their code -- hopefully correctly.
     
    JohnF, Jan 12, 2014
    #68
  9. JohnF

    JohnF Guest

    Oh, yeah, that's what I understood you as saying, and what I intended
    to do, from your previous remarks. Existing ran1() does what's needed.
    The section, starting on page 278 of Numerical Recipes in C, 2nd ed,
    discusses (and provides code for) several rng's, including some tests.
    Based on all that, you're right, I tacitly assumed ran1() okay.
    Or okay enough. And, in any case, my fm.html page has a short
    "Random number generation" <h3> section that ends up with
    the "cya" remark,
    "Of course, you're welcome to replace the "stock" versions of ran1( )
    and rseeder( ) supplied in fm.zip with any other code of your own
    choosing (keeping the same calling sequences, etc)."
     
    JohnF, Jan 12, 2014
    #69
  10. Well, pretty much int is the word size of the machine. On a PDP-11
    or even 8 bit processors, int is usually 16 bits. Also, for the
    early MS-DOS machines, before the 80386, and to later machines.

    But VAX is a 16 bit word machine, but I would expect 32 bit int
    for it, though I don't remember what VAX-C does.

    The tradition from some years ago was to use short for 16 bits,
    long for 32, but that got confusing when 64 bit systems came out.

    -- glen
     
    glen herrmannsfeldt, Jan 12, 2014
    #70
  11. (snip, I wrote)
    And, of course, using floating point there isn't any bias...

    -- glen
     
    glen herrmannsfeldt, Jan 12, 2014
    #71
  12. JohnF

    JohnF Guest

    Fyi, the solution I've now coded was based on Eric's preceding (but
    snipped here) discussion. His formula was a little opaque to me,
    so I googled the keywords he introduced to come up with the following,
    which is pseudocoded below from the real code in forkosh.com/fm.zip,
    int iran1 ( int ilo, int ihi ) { /* you want int rn from ilo to ihi */
    long ran1(/*some args go here*/), /*original rng from Numerical Recipes*/
    iran = ran1(/*args*/), /* integer result from rng */
    range = ihi-ilo+1, /* ihi-ilo+1 */
    IM = 2147483647, /* ran1()'s actual range is 1...IM */
    imax = IM - (IM%range); /* force iran's max to a multiple of range */
    while ( iran >= imax ) iran=ran1(/*args*/); /*discard out-of-range iran*/
    return ( ilo + (iran%range) ); } /* back with random ilo <= i <= ihi */
     
    JohnF, Jan 12, 2014
    #72
  13. JohnF

    Ike Naar Guest

    Isn't ran1()'s actual range [1..2147483646] ?
     
    Ike Naar, Jan 12, 2014
    #73
  14. JohnF

    J. Clarke Guest

    I'm no expert but one thing I learned <mumble> years ago was to make
    sure that the problem you're chasing really is the problem you _think_
    you're chasing. You've got three different versions of the compiler
    with two of them giving one behavior and the third, oldest one giving a
    different behavior, which you are attributing to 64 bit vs 32-bit. It
    could also be the result of some change made to the more recent releases
    of the compiler and I would want to rule that out rather than assuming
    that it's a 32- vs 64- bit issue.
     
    J. Clarke, Jan 12, 2014
    #74
  15. Most modern *hosted* implementations make int 32 bits, but there's
    nothing deprecated or archaic about 16-bit int (at least as far as the C
    standard is concerned).

    POSIX requires at least 32 bits, so if your program already depends on
    POSIX features, you can safely make that assumption. Otherwise, you can
    certainly assume 32-bit or wider int if you want to, but I personally
    would take care to make that assumption explicit, so if someone tries to
    compile my code with a fully conforming implementation that happens to
    have 16-bit int the problem will be detected early.

    #include <limits.h>
    #if INT_MAX < 2147483647
    #error This code requires at least 32-bit int
    #endif

    [...]
    Note how the warning is phrased: "ISO C90 does not support 'long long'".
    The long long type has been a standard C feature since the 1999 standard
    (and a common extension before that). Failure to support long long is
    not merely deprecated, it's completely non-standard. If you're willing
    to assume that int is at least 32 bits, you should be even more willing
    to assume that long long exists.

    And <stdint.h> also did not exist in C90; both it and long long were
    introduced by C99.

    Just invoke your compiler with options to tell it to use a more modern
    version of the language.

    gcc in particular uses "-std=gnu89" by default, which is C89/C90 with
    GNU extensions. IMHO this is unfortunate, and it's time for gcc to
    support C99 by default. But it probably doesn't make much sense to rely
    on gcc's default anyway.

    If you need your code to be portable to Microsoft's compiler, you might
    have a problem; I don't remember whether it supports long long, but I
    know it doesn't support C99 or C11.
     
    Keith Thompson, Jan 12, 2014
    #75
  16. JohnF

    jacob navia Guest

    Le 12/01/2014 22:09, Keith Thompson a écrit :
    A system with sizeof(int) of 16 bits will have problems with the above
    constant "2147483647" since it is an integer constant that overflows
    thompson

    i would rather write

    #if INT_MAX < 2147483647L

    since long must be at least 32 bits


    conclusion:
     
    jacob navia, Jan 12, 2014
    #76
  17. JohnF

    Kaz Kylheku Guest

    GCC's warnings about "long long" in C90 code (-ansi) are not a consequence of
    -Wall. They are a consequence of -pedantic.

    "long long" is a conforming extension to C90: it relies on grammar which
    is a syntax error in C90, requiring a diagnostic.

    The -pedantic mode means "generate all standard-required diagnostics" (or
    rather, make an effort to do that, modulo bugs and omissions).

    Try the following with "gcc -Wall -ansi". The only diagnostic you get is
    about the unused variable:

    #include <stdio.h>

    long long x;

    int main(void)
    {
    printf("hello, world\n");
    int declaration_after_statement = 0;
    return 0;
    }

    If you don't use -pedantic, you risk accidentally using extensions that you
    don't intend to use. The cure for that is to compile your code base with
    -pedantic once in a while and fix everything that you care to fix.
     
    Kaz Kylheku, Jan 12, 2014
    #77
  18. No. What matters is the types intmax_t and uintmax_t and they can't be
    anything like as small as 16 bits. See 6.10.1p4.

    <snip>
     
    Ben Bacarisse, Jan 12, 2014
    #78
  19. They may be numerical tests based on the floating point value. It will
    make almost no difference to a numerical test if the bottom bit of the
    int (just before the final divide) cycles 0,1,1,0,1,1,0,... (for
    example) but it will make a big difference if you make binary choices by
    using ran1(...) & 1. Eric S suggests that this sort of thing does not
    happen with the PRNG you use, but I'd not seen that post when I wrote.
    Assuming that the floats are well distributed, is not quite the same as
    assuming that the ints have all the right properties so a test or two
    would not go aims.

    <snip>
     
    Ben Bacarisse, Jan 12, 2014
    #79
  20. JohnF

    Ike Naar Guest

    1.6.10 p4:
    "For the purposes of this token conversion and evaluation, all
    signed integer types and all unsigned integer types act as if they
    have the same representation as, respectively, the types intmax_t
    and uintmax_t defined in the header <stdint.h>."

    The maximum value of type intmax_t, INTMAX_MAX, is required to be
    at least (2 to the power 63) - 1 (see 7.20.2.5 p1),
    so 2147483647 <= INTMAX_MAX, and therefor "#if INT_MAX < 2147483647"
    is valid even on implementations where INT_MAX < 2147483647,
     
    Ike Naar, Jan 12, 2014
    #80
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.