• (disco)

    Doesn't double / int return a double and perform proper division and NOT integer division?

    TRWTF is whoever wrote that.

  • (disco) in reply to aliceif

    It's also possible that the author wanted to annotate each part of the expression with a type, "for the benefit of the reader".

    I guess we'll never know.

  • (disco)

    I briefly wondered if Convert.ToInt32 could actually take an Int32 as a parameter. As it turns out, yes. It even specifies that the function does nothing.

    aliceif:
    Doesn't double / int return a double and perform proper division and NOT integer division?
    Yeah, the code could have been written without any casts at all:
    private string GetPercentage(Int32 EducationTotal) {
      return (EducationTotal * 100.0 / Total).ToString("N2");
    }
    
    JBert:
    It's also possible that the author wanted to annotate each part of the expression with a type, "for the benefit of the reader".
    And yet he didn’t completely parenthesize the expression, possibly leaving the reader wondering if C# evaluates multiplication before division or not.
  • (disco) in reply to aliceif
    aliceif:
    Doesn't double / int return a double and perform proper division and NOT integer division?
    Yep; the compiler auto-elevates the `int` to a `double`, then does floating-point division. So, whether `Total` is an `int` or not is irrelevant; the end result of the calculation will be a `double`.
  • (disco) in reply to aliceif
    aliceif:
    Doesn't double / int return a double and perform proper division and NOT integer division?

    TRWTF is whoever wrote that.

    Yup it does. Embellishment, schmembellishment.
  • (disco) in reply to VinDuv
    VinDuv:
    And yet he didn’t completely parenthesize the expression, possibly leaving the reader wondering if C# evaluates multiplication before division or not.
    Well, I'd suggest that C# does indeed "evaluate multiplication before division or not". It does it one way round **or** the other way round, depending on ... um ... stuff.

    And I do think that TJ should meet the cluebat, a bit. The description of the cast-to-double-then-divide is just so much gibberish. There's also my C/C++ head that suggests that cast-to-int might change the type of an Int32 value, platform permitting, but I'm also aware that C# doesn't follow those rules, so I avoid the cluebat, this time.

    Then again, I once worked in a C/C++ (with a bit of x86 assembler in the mix) shop where the development manager, allegedly himself a C/C++ programmer, freely admitted that he didn't get pointers. (I found this out about a year after I joined them. For unrelated reasons I left about six months later.)

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    allegedly himself a C/C++ programmer, freely admitted that he didn't get pointers

    That's like a journalist saying they don't understand letters

  • (disco) in reply to Jaloopa
    Jaloopa:
    That's like a journalist saying they don't understand letters
    Yeah, it made me blink when he said it. I mean, OK, there's a lot of weirdness that comes out of C's approach to pointers, but it isn't **that** hard, and not getting them causes such pain.
  • (disco)

    (int)(Convert.ToInt32(StudentCount)

    Step 1: Ensure that the number of students is less than or equal to 2,147,483,647. Step 2: For 64 bit machines, promote to Int64 to allow for more students in a later calculation.

  • (disco) in reply to aliceif
    aliceif:
    Doesn't double / int return a double and perform proper division and NOT integer division?

    Yup, it does.

    Reminds me: I once worked on a compiler for a Digital Alpha, and integer division (int/int) simply meant that the compiler transferred the two numbers into the math processor, did the division, and then transferred the result back into the main cpu as an integer. My task (which actually is a nice coding challenge) was to do it properly using only integers.

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    Well, I'd suggest that C# does indeed "evaluate multiplication before division or not". It does it one way round or the other way round, depending on ... um ... stuff.

    Huh? C#, like most C like languages (and Python, at least) give the same order of precedence to * and / and evaluate left-to-right, so “a / b * c” is always interpreted as “(a / b) * c”.

  • (disco) in reply to VinDuv

    Woosh much?

  • (disco) in reply to VinDuv
    VinDuv:
    Huh? C#, like most C like languages (and Python, at least) give the same order of precedence to * and / and evaluate left-to-right, so “a / b * c” is *always* interpreted as “(a / b) * c”.
    Hmm. Fair point, although I think, for floating operations, that you may find that things actually happen in an order specified by the compiler, not by the language (for C/C++, YMMV for C#). (For int-int operations, the order is important - 5/4*4 is not a no-op in pure-integer maths, so evaluating it as equivalent to 5*4/4 gets the wrong answer.)

    As always, if you feel the need to have fine-grained control of the way in which sub-expressions are evaluated, use the tools provided by the language (round brackets, intermediate assignments, etc.).

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    Well, I'd suggest that C# does indeed "evaluate multiplication before division or not". It does it one way round **or** the other way round, depending on ... um ... stuff.
    Multiplication and division precedence can be swapped without changing the result of the calculation. Having said that, IIRC, C# always does it left-to-right.
    lcrawford:
    Step 2: For 64 bit machines, promote to Int64 to allow for more students in a later calculation.
    In C#, `int` == `Int32` by definition.
  • (disco) in reply to RaceProUK
    RaceProUK:
    Multiplication and division precedence can be swapped without changing the result of the calculation.

    (100 / 3) * 5 != 100 / (3 * 5)

  • (disco) in reply to VinDuv
    VinDuv:
    `(100 / 3) * 5 != 100 / (3 * 5)`
    :headdesk:
  • (disco) in reply to VinDuv
    VinDuv:
    `(100 / 3) * 5 != 100 / (3 * 5)`
    Correct, but:
    (100.0/3)*5 == (100.0*5/3)
    (100/3)*5 != (100*5)/3
    

    Where the second one is integer operations. The inequality is because 100 does not evenly divide by 3, so there is a loss of precision that gets multiplied up. And, of course, the first one assumes an infinite number of decimal places!

  • (disco) in reply to VinDuv

    Whoosh.

    100 / 3 * 5 == 100 * 5 / 3

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    There's also my C/C++ head that suggests that cast-to-int might change the type of an Int32 value, platform permitting, but I'm also aware that C# doesn't follow those rules, so I avoid the cluebat, this time.

    I wonder if anyone reading that was thrown by that. I mean, unless you know int is C# short-hand for System.Int32, it'd look like you're introducing a new data type.

  • (disco) in reply to aliceif

    Doesn't that depend on the compiler? You can probably bet on the fact that there is some compiler that it even more TRWTF than this code that or some speed-up-reason performs an integer-division in this case. I'd say normal casting to double is not completely terrible in this case.... it's the way it was done that is mindboggeling!

    Filed Under: Compilers are weird sometimes!

  • (disco) in reply to Kuro
    Kuro:
    Doesn't that depend on the compiler?

    Sounds like the kind of thing that would be defined in any sensible spec

  • (disco) in reply to Jaloopa

    I dunno, all I remember from my C++101 is that the GCC allows int array[length]; even though thats against the standard... So pity me for not believing specs and standards anymore!

    Filed Under: sensible is a stretchy word!

  • (disco) in reply to Kuro
    Kuro:
    I dunno, all I remember from my C++101 is that the GCC allows ```int array[length];``` even though thats against the standard... So pity me for not believing specs and standards anymore!

    Filed Under: sensible is a stretchy word!

    Depends. If `length` is declared `const`, and given a value visible in the current scope, then `int array[length];` is allowed by C++.
    const int length = 7;
    int array[length]; // equivalent to int array[7]
    
  • (disco) in reply to Arantor
    Arantor:
    Whoosh.

    100 / 3 * 5 == 100 * 5 / 3

    Not in integer operations, because 100/3 ==> 33, then times 5 ==> 165, whereas 100*5 ==> 500, then divided by 3 ==> 166.
  • (disco) in reply to Steve_The_Cynic

    IIRC GCC allows this:

    int somefunction( size_t len )
    {
        char buffer[len];
        ...
    }
    

    Even in C, if you pass the right flags.

  • (disco) in reply to Steve_The_Cynic

    I was more whooshing over the fact that in precedence terms, * and / will be outranked by the brackets, but if you remove the brackets they are arithmetically equivalent.

    I make no cases against whatever environment you have that makes them ints outside of the expression itself.

    And then you have http://codepad.org/Yx1jPjlr which says everything you need to know about PHP/floating point accuracy.

  • (disco) in reply to Arantor
    Arantor:
    I was more whooshing over the fact that in precedence terms, `*` and `/` will be outranked by the brackets, but if you remove the brackets they are arithmetically equivalent.

    I make no cases against whatever environment you have that makes them ints outside of the expression itself.

    And then you have http://codepad.org/Yx1jPjlr which says everything you need to know about PHP/floating point accuracy.

    Even in FP, they won't be equal, because in both cases, there is a loss of precision in the very least significant bits, but in the divide-then-multiply case, the loss of precision is multiplied by five, while in the multiply-then-divide case, it is not.
  • (disco) in reply to Steve_The_Cynic

    Yes, I realise this. I was just finding it funny that to 11 reported decimal places they were the same :stuck_out_tongue:

  • (disco) in reply to Arantor

    Yes, I thought that was funny, as well. Of course an IEEE 8-byte double has more than 15 decimal digits of precision, so the loss of precision is hidden in the 15th and 16th sig figs, which aren't printed (166.66666666667 is only 14 sig figs).

  • (disco) in reply to Steve_The_Cynic

    And of course this is PHP so it's anyone's guess where it's actually broken.

  • (disco) in reply to Arantor

    it would be broken like that in any language that uses double... It isn't actually a PHP problem, although there might be some issues seeing it when the code is compiled to native x86 code that uses old-style pre-SSE floating point instructions with 80-bit long double types for non-stored intermediate values.

  • (disco) in reply to Steve_The_Cynic

    One might be forgiven for pinning the blame for this stuff on situations that existed before the PHP creators were born.

  • (disco) in reply to Steve_The_Cynic

    My compsci fu is good but an in-depth working of floating point math is something I learned and forgot a long time ago. I mean, I work in PHP :stuck_out_tongue:

  • (disco) in reply to Steve_The_Cynic

    And, as everyone knows, 4,195,835 / 3,145,727 = 1.333739068902037589 no matter how you look at it.

  • (disco) in reply to PleegWat
    PleegWat:
    IIRC GCC allows this:

    int somefunction( size_t len ) { char buffer[len]; ... }

    Even in C, if you pass the right flags.

    $ cat test2.c
    #include <stdio.h>
    
    int func(size_t length)
    {
    	int arr[length];
    
    	return (sizeof(arr) / sizeof(int));
    }
    
    int main(void)
    {
    	int test = func(5);
    
    	printf("%d\n", test);
    
    	return 0;
    }
    $ gcc -o test2.o test2.c
    $ ./test2.o
    5
    $ gcc --version
    gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
    Copyright (C) 2013 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    

    Fine even without any flags here.

  • (disco) in reply to Arantor

    I've spent most of my career dealing with some sort of low-level shit, all the way down to disassembling the output of a C-to-8088 compiler and discovering that this code:

    while( 1 )
      do_some_stuff();
    

    really caused its most aggressive optimisation mode to generate code to load 1 into a register, compare that register to 0, and jump back for another go if they weren't equal.

    We replaced it, by the way, with another compiler that generated code that was about 25% smaller and whose 100% software floating point implementation ran at three times the speed of the old compiler's...

  • (disco) in reply to Steve_The_Cynic

    Yeah, see I never played with anything quite like that.

  • (disco) in reply to lcrawford
    lcrawford:
    Step 1: Ensure that the number of students is less than or equal to 2,147,483,647.Step 2: For 64 bit machines, promote to Int64 to allow for more students in a later calculation.

    I am glad someone else is as paranoid as I am about bad input data. Some years ago I was working with historic data from printers, specifically counting up printed pages. There was a mystery overflow causing arithmetic exceptions, hard to find in the millions of records being processed. It turned out that one model of a particular manufacturer was failing to return counts, but storing the value as -1 and returning it as an unsigned int.

  • (disco) in reply to Jaloopa
    Jaloopa:
    Sounds like the kind of thing that would be defined in any sensible spec

    With stress on "sensible". (A medieval concept, btw.)

    DCRoss:
    And, as everyone knows, 4,195,835 / 3,145,727 = 1.333739068902037589 no matter how you look at it.

    Not if a comma separates expressions. And/or a single equals character marks an assignment.

    Steve_The_Cynic:
    OK, there's a lot of weirdness that comes out of C's approach to pointers, but it isn't that hard, and not getting them causes such pain.

    Plus, it's clear from the syntax what is a pointer and what is not. C# (and VB) does know pointers, but is ashamed to admit it. Refactoring a struct as a class (or - not as frequently - a class as a struct) can lead to a reasonable amount of pain in the back.

  • (disco) in reply to PWolff
    PWolff:
    Plus, it's clear from the syntax what is a pointer and what is not.

    Once again, PHP is TRWTF:

    function doStuff(&param) { .. } // Pass by reference, completely fine
    
    doStuff(&var);                  // Whines about passing by reference being deprecated
    doStuff(var);                   // Passes var by reference, no questions asked
    

    Great, now I don't even know what I passed into the function. Splendid!

  • (disco) in reply to Onyx

    C pointers & PHP references are different things, but IMO the latter should never be used (unless you like magic unexpected shit happening just by calling functions/methods).

  • (disco) in reply to Onyx

    Yes, they're not deprecating passing references into functions, only the implicit situation of passing something in as a reference that wasn't supposed to be a reference.

    Passing by reference in general is kind of voodoo and generally should be avoided. It's usually the hallmark of an older application or someone coming to PHP from another background (e.g. I know one library I tried to work with had all its methods as accepting references and acting on the references themselves so the methods would all return bools for success/failure)

  • (disco) in reply to monkeyArms
    monkeyArms:
    C pointers & PHP references are different things, but IMO the latter should never be used

    I was commenting the clarity remark, not equating pointers and references.

    And I did use references at times. Works fine if you're really careful about it.

    Arantor:
    Passing by reference in general is kind of voodoo and generally should be avoided.

    Which I did. And would keep avoiding it, but the damned thing doesn't have method overriding!

  • (disco) in reply to Onyx
    Onyx:
    the damned thing doesn't have method overriding!

    Sure it does (assuming you're talking about child class methods)?

  • (disco) in reply to monkeyArms
    monkeyArms:
    Sure it does (assuming you're talking about child class methods)?

    Honestly, I have to look into my code / docs. I had some reason for doing it.

    Also, checked, you're right, overriding works, overloading doesn't.

  • (disco) in reply to Onyx

    This kind of overloading? It works a little differently than most languages but it's there.

  • (disco) in reply to monkeyArms

    Yes, you can do it using __call. Which can also be a pain, depending on what you're trying to do. Luckily, I didn't need it much / at all. Though I did abuse __call for all kinds of other ugly shit I'd rather not think about (or admit to).

  • (disco) in reply to monkeyArms
    monkeyArms:
    [This][1] kind of overloading? It works a little differently than most languages but it's there. [1]: http://php.net/manual/en/language.oop5.overloading.php
    Oh sweet merciful Chaos keep that shit away from me…

    I've just redefined my own personal hell to include eternity developing in PHP :smile:

  • (disco) in reply to RaceProUK
    RaceProUK:
    I've just redefined my own personal hell to include eternity developing in PHP

    That's cool, more money for me :monkey_face:

  • (disco) in reply to Onyx

    Don't forget func_get_args() is a thing for really shitty overloading.

Leave a comment on “When You Really Want to be Sure it's an INT”

Log In or post as a guest

Replying to comment #:

« Return to Article