Hello Luiz !
Thank you for the link !
But what still bugs me is the difference between heavily used
programming languages:
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)
Really Too many extra parentheses (notably around constants) having no purpose in this test!
SQUILU = 8515287402650.3
SQLITE = 8515287402650.34
POSTGRESQL = 8515287402650.347200
D = 8.51529e+12
JAVA = 8.515287402650345E12
All the same, just different formatting (using 64-bit IEEE "double"): this should be tested in C/C++, but beware of portability of "float/double" in terms of precision, and also in terms of type promotion (notably when operands are integers, and not explicitly changed to double using ".0" at least in the constants: this impacts notably divisions, not just modulos; beware also of the current rounding mode: truncate towards 0 for operations on integers, but *normally* (by default in C/C++ compliant apps, and if not using IEEE control functions to change the rounding mode) rounding to the least significant bit to the nearest even for doubles; floats are always implicitly promoted to doubles in C/C++).
Note that in Java there are also a subtle setting that allows not rounding ever operations at each step, but only at end (this is an optimization for speed, the default should use strict mode where rounding occurs at each operation. _javascript_ has also such settings in some implementations via "hints".
MYSQL = 8259816920501.086
_javascript_ = 8259816920615.111
PHP = 8259816920615.1
LUA = 8259816920615.1
AMPL = 8.25982e+12
GAMS = 8.25982E+12
all the same, just different formatting (here all constants are used as if they were doubles, _javascript_ or Lua may try to "optimize" operations on integers but will avoid overflows by converting the result to doubles, both Lua and _javascript_ has a single "number" type allowing "double" precision, even if they may use subtypes for optimizations... when they are safe).
PHP is not clear at all about what it does and when it performs rounding. In doubt, use intermediate storage variables to force the rounding in the stored value of the variable, which should then be used to compute the rest.
RUBY = 7701542593121.873
PYTHON = 7.70154259312e+12
Severe differences here caused by divisions (without implicit promotion to doubles). Note that parentheses play a role in terms of associativity and commutativity: permuting operands is not valid if this causes an operator to change the promotion of integer operands to doubles when the other operand may change from an integer to a double. Some languages may also change the priority of operators, and the associativity may be changed if the _expression_ is computed at runtime and not in the compiler itself (for constants) so that it may impact the precision of the result, but the compiler should have optimization hints to allow or disallow such change.
Each language defines how operands are promoted, how operations are rounded (depending on types if they support multiple numeric types; this is not the case of Lua and _javascript_, but occurs in Java). You could test it again in other languages: C#, J#, Rust, or Mathematica (which should give the best precision, using a single numeric datatype for reals)... Other languages to consider: Perl, Scheme, Fortran, F#... and COBOL (computing by default with enforced precision in decimal with many numeric datatypes scoped by their "format"), and assembly languages (supporting expressions of constants, in their macroprocessor and in some operands)
We could also speak about preprocessors for C/C++ (which have their own limits independant of the language they target, but usually preprocessors can only compute small integers for evaluating directives and offer a smaller valid range of values and operators, otherwise they treat expressions like strings without computing them, leaving the compiler of the target language evaluate them where needed).