[HN Gopher] Incorrect expression calculation between programming...
       ___________________________________________________________________
        
       Incorrect expression calculation between programming languages
        
       This expression shows that we have several disagreements between
       programming languages about what is the end result:  =====  EXPR = 
       (((((((788)*(8.46))))+8342*1.803-1))*4186.4*(15))*(((22%284/((7530/
       ((2)*(((((25))-421))))))*597%2663)+7283.8-9.60+167.8644%((3))))+(88
       71)  POSTGRESQL = 8291561284461.33301440  SQUILU = 8291561284461.3
       JAVA = 8.291561284461331E12  D = 8.29156e+12  SQLITE =
       8290383058308.3  PHP = 8035491468054  JAVSCRIPT = 8036090802426.098
       MYSQL = 8036090802312.071  PYTHON = 1.1107636287e+13  RUBY =
       11107636286950.146  LUA = 11665910614443  =====
        
       Author : mingodad
       Score  : 59 points
       Date   : 2021-08-06 11:24 UTC (1 days ago)
        
       | mingodad wrote:
       | And making all operands to modulo operator "%" integer:
       | 
       | =====
       | 
       | EXPR = (((((((788)*(8.46))))+8342*1.803-1))*4186.4*(15))*(((22%28
       | 4/((7530/((2)*(((((25))-421))))))*597%2663)+7283.8-9.60+167%((3))
       | ))+(8871)
       | 
       | D = 8.29038e+12
       | 
       | JAVA = 8.290383058308305E12
       | 
       | MYSQL = 8034912576159.046
       | 
       | POSTGRESQL = 8290383058308.307200
       | 
       | SQLITE = 8290383058308.3
       | 
       | SQUILU = 8291561284461.3
       | 
       | JAVASCRIPT = 8034912576273.071
       | 
       | PHP = 8035491468054
       | 
       | AMPL = 8.03491e+12
       | 
       | GAMS = 8.03491E+12
       | 
       | PYTHON = 1.11064580608e+13
       | 
       | RUBY = 11106458060797.121
       | 
       | LUA = 11664732388290
       | 
       | ====
        
       | mingodad wrote:
       | After removing all modulo operations and transforming all numbers
       | to floating point:
       | 
       | ====
       | 
       | EXPR = (((((((788.0) _(8.46))))+8342.0_ 1.803-1.0)) _4186.4_
       | (15.0)) _(((22.0 /((7530.0/((2.0)_(((((25.0))-421))))))*597.0)+72
       | 83.8-9.60+167.0))+(8871.0)
       | 
       | SQUILU = 8259816920615.1
       | 
       | LUA = 8259816920615.1
       | 
       | JAVASCRIPT = 8259816920615.111
       | 
       | SQLITE = 8259816920615.11
       | 
       | POSTGRESQL = 8259816920615.11377654520912550160000
       | 
       | MYSQL = 8259816920615.113
       | 
       | AMPL = 8.25982e+12
       | 
       | PHP = 8259816920615.1
       | 
       | RUBY = 8259816920615.111
       | 
       | PYTHON = 8.25981692062e+12
       | 
       | ====
        
         | ayjtyjtyj wrote:
         | See this interesting paper on the possible choices of
         | definition for div and mod:
         | 
         | RT Boute, "The Euclidean definition of the functions div and
         | mod" (1992)
         | 
         | https://biblio.ugent.be/publication/314490/file/452146.pdf
        
         | [deleted]
        
         | miga wrote:
         | Your expressions omits many necessary operators, and thus
         | becomes ambiguous.
        
           | comex wrote:
           | It's because Hacker News parsed the asterisks in the
           | expression as italic markers.
        
       | psyklic wrote:
       | This is solely due to differences in the / and % operators:
       | # int/int -> int       POSTGRESQL = 8291561284461.33301440
       | SQUILU = 8291561284461.3       JAVA = 8.291561284461331E12
       | D = 8.29156e+12            # int/int -> float       LUA =
       | 11665910614443       PYTHON3 = 11665910614443.387            #
       | int/int -> float, UNIQUE: pos%neg -> neg       JAVSCRIPT =
       | 8036090802426.098       MYSQL = 8036090802312.071      # single-
       | precision FLOAT            # int/int -> int, UNIQUE:
       | negint/posint -> negint (the floor)       PYTHON2 =
       | 1.1107636287e+13       RUBY = 11107636286950.146            #
       | int/int -> int, UNIQUE: negfloat%posint -> negint (the ceil)
       | SQLITE = 8290383058308.3            # int/int -> float, UNIQUE:
       | negfloat%posint -> negint (the ceil)       PHP = 8035491468054
        
         | begueradj wrote:
         | interesting note
        
         | specialist wrote:
         | Interesting.
         | 
         | What's the correct answer?
         | 
         | Which programming languages specify which parts of IEEE 754
         | they follow (or not)?
         | 
         | https://en.wikipedia.org/wiki/IEEE_754
         | 
         | Ditto rendering of floating point numbers. Here's a prior
         | thread about Steele & White, Grisu, Ryu:
         | 
         | "Here be dragons: advances in problems you didn't even know you
         | had" https://news.ycombinator.com/item?id=24917659
        
           | kazinator wrote:
           | They are possibly all correct.
           | 
           | Correct means that the requirements of a documented
           | specification are being followed.
        
           | rmah wrote:
           | There is no correct answer. There is no correct answer. The
           | various ways different languages handle implicit type
           | conversion with division and modulo operations are all both
           | correct and incorrect at the same time. It's really an
           | arbitrary choice. In fact, there are more choices than
           | presented above. I think, for example, Perl6, uses rational
           | numbers in some of the above situations.
        
           | chowells wrote:
           | The correct answer is not making the computer guess what you
           | mean. That's the root problem here. You're being super-sloppy
           | about specifying what actual operations you want to take
           | place. What are the types of the operands? What are the
           | semantics of the arithmetic operators for the pairs of
           | operand types you get?
           | 
           | Without bothering to tell the computer what you want for the
           | types or select the correct operators for the types you
           | provided, you're falling back on guessing. Not every language
           | guesses the same way, because not every language designer has
           | the same guess what people meant.
           | 
           | My ideal is a language that tells you that expression is bad
           | and to actually clarify what you mean. But a lot of people
           | seem to hate having to explicitly communicate their intent.
        
           | [deleted]
        
           | guenthert wrote:
           | Well, ideally you'd want to treat int/int -> rational. The
           | original form is quite obfuscated, some of the parentheses
           | are to enforce evaluation of the given string as number (and
           | the various programming languages will differ as what number
           | that'll be, due to representation of decimal fractions and
           | type conversion), some parenthesis are plainly superfluous,
           | yet still there is remaining ambiguity (how is a%b/c to be
           | interpreted? Most programming languages will do this
           | left->right, but better make that explicit). Prefix notation
           | to the rescue:
           | 
           | Common Lisp (with *read-default-float-format* -> SINGLE-
           | FLOAT)
           | 
           | CL-USER> (+ (* (+ (* 788 8.46) (1- (* 8342 1.803))) 4186.4 15
           | (+ (* (/ (mod 22 284) (/ 7530 (* 2 (- 25 421) (mod 597
           | 2663))))) 7283.8 -9.60 (mod 167.8644 3))) 8871)
           | 
           | 8.03609e12
           | 
           | Wolfram Alpha finds for
           | (((((((788)*(8.46))))+8342*1.803-1))*4186.4*(15))*(((mod [22,
           | 284]/((7530/((2)*(((((25))-421))))))*mod[597,
           | 2663])+7283.8-9.60+mod[167.8644, ((3))]))+(8871)
           | 
           | 8.03609080242609957376254980079681274900398406374501992031872
           | *10^12
        
           | mjn wrote:
           | IEEE 754 doesn't really have anything to say about which
           | semantics you should choose for int/int division. _If_ you
           | choose the semantics of casting both operands to floating
           | point and then dividing, IEEE 754 specifies both 1) how the
           | int- >float conversion should happen, and 2) how the
           | float/float division should happen. But if you choose the
           | semantics that int/int division returns an int without any
           | floating-point conversions (like C's '/' operator), then no
           | floating point numbers enter into the question at all, and
           | it's out of scope for IEEE 754.
        
             | _moof wrote:
             | Over thirty years of programming I've slowly become
             | convinced that implicit conversions are the devil.
        
               | andi999 wrote:
               | This devil allows high productivity though.
        
               | andybak wrote:
               | Must be down to all those idle hands he can bring to bear
               | on a given task.
        
               | tialaramex wrote:
               | Not everybody is convinced that it's "more productive" to
               | produce more bugs.
        
               | jl6 wrote:
               | Bingo. When performance is the overriding goal, it is
               | often a matter of choosing which deals to do with which
               | devils.
        
       | Pinus wrote:
       | So, we have (at least) different evaluation orders, different
       | meanings of the % operator (How are negative numbers handled?),
       | different meanings of the / operator (is 10/3=3 or 3.3333 --
       | notice that Python3 joins the 8.29e+12 fold!). This shows two
       | things: 1) Even though it is syntactically correct in N different
       | languages, it does not necessarily mean the same thing, and 2)
       | floating-point math has many traps. Neither should be news to the
       | HN readership.
        
       | hansvm wrote:
       | This kind of thing can bite you even when operating purely on
       | integers. E.g., for a long time (it's been fixed for over a dozen
       | years by now though), Python implemented x%n with an intermediate
       | cast to float, with predictably bad results on inputs larger than
       | typical test cases. I had the damnedest time tracking down the
       | culprit since I assumed it had to be serialization, hashing, or
       | one of the standard culprits --- not that integer math was
       | broken.
        
         | [deleted]
        
       | mingodad wrote:
       | And after removing all modulo operations:
       | 
       | ====
       | 
       | EXPR = (((((((788)*(8.46))))+8342*1.803-1))*4186.4*(15))*(((22/((
       | 7530/((2)*(((((25))-421))))))*597)+7283.8-9.60+167))+(8871)
       | 
       | SQUILU = 8515287402650.3
       | 
       | SQLITE = 8515287402650.34
       | 
       | POSTGRESQL = 8515287402650.347200
       | 
       | D = 8.51529e+12
       | 
       | JAVA = 8.515287402650345E12
       | 
       | MYSQL = 8259816920501.086
       | 
       | JAVASCRIPT = 8259816920615.111
       | 
       | PHP = 8259816920615.1
       | 
       | LUA = 8259816920615.1
       | 
       | AMPL = 8.25982e+12
       | 
       | GAMS = 8.25982E+12
       | 
       | RUBY = 7701542593121.873
       | 
       | PYTHON = 7.70154259312e+12
       | 
       | ====
        
         | oshiar53-0 wrote:
         | PYTHON3 = 8259816920615.111
        
         | fishmaster wrote:
         | Julia 1.3.1: 8.259816920615111e12
        
         | tromp wrote:
         | bc -l = 8259816920615.11375936705619635555
        
       | [deleted]
        
       | svnpenn wrote:
       | You couldnt come up with a simpler example? Youve got at least 12
       | operations there. Pretty much a single division operation wouldve
       | worked about the same
        
       | banana_giraffe wrote:
       | Different languages have different rules around some math
       | operators, notably around order of operations and how % and /
       | handle floating point values. There are much simpler expressions
       | that will yield differences.
       | 
       | Also, you appear to be using Python 2, the results are different
       | with any modern version of Python.
        
         | banana_giraffe wrote:
         | And here are the two differences I think your expression is
         | hitting on:                   Expression: 750/300
         | Python 2.7: 2         Python 3.9: 2.5         C: 2.000000
         | SQLite: 2         Node: 2.5         Java: 2         Go: 2
         | Expression: -123%10         Python 2.7: 7         Python 3.9: 7
         | C: -3.000000         SQLite: -3         Node: -3         Java:
         | -3         Go: -3
         | 
         | There might be more. Though, there's a ton of needless
         | obfuscation in your expression.
        
           | unwind wrote:
           | Certainly not floating point results in C for either of
           | those.
           | 
           | All literals shown (750, 300, -123 and 10) are of type 'int',
           | so the results would be, too.
        
             | banana_giraffe wrote:
             | Yep, I coerced the result to floating point in my harness.
             | 
             | If anyone cares to look: https://pastebin.com/7tLrs28V
             | 
             | I'm probably done, it's a mildly interesting side quest,
             | but really, this is just reinforcing that different
             | languages do things differently.
        
       | MauranKilom wrote:
       | Other than nerdsniping, what is the point of this expression?
       | 
       | If you wanted to show how different languages treat modulo, type
       | conversions, division, etc., you could just show individual
       | examples. That would be significantly clearer.
       | 
       | Was there some practical reason behind creating this expression,
       | or is it just obfuscation?
        
       | hinkley wrote:
       | A big part of the oft-overlooked notion of Information
       | Architecture are the twin concepts of Source of Truth and System
       | of Record. Many systems mix or conflate the two or don't consider
       | them at all, other than subconsciously when wrestling with issues
       | of code duplication (split SoT).
       | 
       | If the result of a calculation is that important to the
       | functioning of your code, then having three implementations in
       | multiple languages is just madness. You need to pick one to
       | believe, or constantly deal with random catastrophes. Personally
       | I enjoy very much not being woken up at 7 am EST to solve
       | production issues. Almost as much as I hate other people getting
       | kudos for problems that we should have not signed up for in the
       | first place. Arsonist-firefighters exist in every dark corner of
       | the programming world, and in much greater numbers than actual
       | arsonist-firefighters.
       | 
       | From a technology selection standpoint, all of this info is
       | extremely important, because it will inform both my choice of
       | tools and my immediate task list to deal with any answers I don't
       | like. But if you're wrestling with this every day, you've already
       | fucked up.
        
       | NotSwift wrote:
       | These are some shocking differences. How did you come up with
       | this expression?
        
         | mingodad wrote:
         | After looking for a text generator for grammars I found this
         | https://github.com/dmbaturin/bnfgen and then to try understand
         | the underlying algorithm I came out with a C simple program for
         | a simple expr grammar see it here
         | https://github.com/dmbaturin/bnfgen/issues/2#issuecomment-89...
         | and also a thread on sqlite forum here
         | https://sqlite.org/forum/forumpost/6885cf9e21
        
       | fishmaster wrote:
       | Julia 1.3.1: 8.036090802426098e12
        
       | gus_massa wrote:
       | Try to edit your post and add a \ before each * so it is not
       | interpreted as italics here.
       | 
       | Have you tried to simplify it? My guess is that the problem is
       | not in the last "+(8871)".
        
         | [deleted]
        
       | miga wrote:
       | Haskell: =====
       | 
       | (%) = Data.Fixed.mod'
       | 
       | expr :: Double = 8.036090802426098e12
       | 
       | expr :: Rational = 630330872315297185317 % 78437500
       | 
       | fromRational (expr :: Rational) :: Double = 8.0360908024261e12
        
       | amichal wrote:
       | Fairly early on in my career I was on a team writing a GUI
       | programming environment (think old school flow charts) that
       | generated ASP (classic) or Java backends. We allowed simple
       | expressions in assignments with the basic arithmetic operators
       | and functions. We parsed them into a tiny AST and output Java or
       | ASP code for them with lots of explicit parens and casts. After
       | fiddling with minor differences in precedence, associativity and
       | implicit casts we still had some cases that did not match.
       | Pairing with a more senior dev we wrote a C program to generate
       | and compare a large number (tens of millions) of random
       | expressions trying to explore the important variables (small and
       | large floats. Floats that cause funny rounding. Long sequences of
       | almost the same precedence etc).
       | 
       | We got all three languages to agree to full precision for almost
       | every case but in each run there were stubbornly alway a few
       | dozen we couldn't get to match for non obvious and seeming random
       | reasons.
       | 
       | This was a prototype that never saw real production use and we
       | spent a couple of weeks on it... it always bothered me that we
       | never understood that last 0.00001%
        
       | SavantIdiot wrote:
       | You can't hold a language responsible for "mistakes" if you don't
       | understand how the language works. Quotes intentional.
        
       | anthropodie wrote:
       | For Go, we get compilation error
       | 
       | ./prog.go:8:129: invalid operation: 167.864 % 3 (operator % not
       | defined on untyped float)
        
       | ben-schaaf wrote:
       | It's hardly incorrect that different languages have different
       | semantics, especially considering the mix of types and use of %
       | in that expression. You could just as well complain that they
       | don't all print floating point numbers in the exact same way.
        
       | brudgers wrote:
       | And that is why people still use FORTRAN.
        
         | mingodad wrote:
         | Using https://www.onlinegdb.com/online_fortran_compiler
         | 
         | FORTRAN = 8.51528699E+12
         | 
         | ====
         | 
         | Program Hello
         | 
         | Print *, (((((((788)*(8.46))))+8342*1.803-1))*4186.4*(15))*(((2
         | 2/((7530/((2)*(((((25))-421))))))*597)+7283.8-9.60+167))+(8871)
         | 
         | End Program Hello
         | 
         | ====
        
       ___________________________________________________________________
       (page generated 2021-08-07 23:02 UTC)