Page 1 of 2
Small incompatibility with mod operator/function
Posted: Mon Feb 22, 2021 9:01 am
by ArneOrtlinghaus
One of our beta test customers discovered a small incompatibility for the mod function. Mod is not only defined for integers, but should be valid also for float numbers.
f := mod(2.6, 0.5) -> VO: 0.1 X#: Exception
f := mod(2.6, 2) -> VO: 0.6 X#: 0
It makes really sense using floats in the mod function, if you have to distribute articles quantities into packages:
- over all quantity of 2.6 liters to be shipped.
- Packages of 0.5 liters
-> 5 packages of 0.5 liters can be sent plus a remainder of 0.1 liters.
Arne
Small incompatibility with mod operator/function
Posted: Mon Feb 22, 2021 9:05 am
by Chris
Hi Arne,
Mod() is indeed defined also for floating point operations. I tried your samples and they seem to work fine, but maybe it is a combination of compiler options that causes the problem. Can you please post a full sample project reproducing this problem, so we can have a look into it and fix it?
Small incompatibility with mod operator/function
Posted: Mon Feb 22, 2021 9:12 am
by ArneOrtlinghaus
Hi Chris,
thank you for answering so quickly. I have sent you an example via email. Probably it depends on compiler settings and variable types used.
Arne
Small incompatibility with mod operator/function
Posted: Mon Feb 22, 2021 9:55 am
by ArneOrtlinghaus
Chris has already found the reason: Usage of usuals as arguments. As a workaround I can help the compiler with casting types: f := Mod(FLOAT(u), fn) with u as usual, fn as float. Having floats or ints as arguments everything works correctly.
Arne
Small incompatibility with mod operator/function
Posted: Mon Feb 22, 2021 10:33 am
by Chris
Hi Arne,
Unfortunately it's even more complicated than that, see
https://github.com/X-Sharp/XSharpPublic/issues/571 for some more cases.
The problem is that we tried to make the Mod() function more efficient than in VO, by providing overloads for different parameter types, but this means that now it's up to the compiler to decide at compile time how to handle the expression, without knowing in advance what the params will represent at runtime.
We could remove the overloads and provide a single Mod() function with USUALs as in VO and make it 100% VO compatible, but this would require a full rebuild of all 3rd party libraries, which is probably better to avoid for now, since the next build will already contain several changes.
Is the workaround with the FLOAT() conversion sufficient enough for you for now?
Small incompatibility with mod operator/function
Posted: Mon Feb 22, 2021 10:42 am
by ArneOrtlinghaus
Hi Chris,
I think that the workaround is ok for us. I will try it the next days. There shouldn't be many occurrences like this in our code. In any case it seems to be an ugly solution that has been used here.
Arne
Small incompatibility with mod operator/function
Posted: Wed Feb 24, 2021 3:40 pm
by ArneOrtlinghaus
I am now changing our occurrences with float or usual parameters.
It is interesting how many effects someone can find out in long running programs.
The result for mod(2, 0.2) is not 0 as someone could imagine. It is 0.2!
But this result in X# is equal in C#, VO, Python.
mod(20.0, 2.0) gives 0 in all these programs.
Arne
Small incompatibility with mod operator/function
Posted: Wed Feb 24, 2021 3:46 pm
by ArneOrtlinghaus
Small incompatibility with mod operator/function
Posted: Wed Feb 24, 2021 6:28 pm
by robert
Arne,
It is even worse than that in VO:
The VO runtime uses inline assembler and the Numeric coprocessor for calculations.
What happens is this:
- The input for the Mod() function are 2 64 bit floating point numbers (REAL8)
- In the inline assembler these 2 numbers are loaded in the floating point registers in the coprocessor. These registers are not 64 bits but 80 bits, so a conversion takes place (this is done with the FLD QWORD PTR instruction)
- The modulo operation is performed on 2 80 bits numbers and the result is a new 80 bits number
- The result is converted back from 80 bits to 64 bits (this is done with the FSTP QWORD PTR instruction)
So there are "rounding errors" on 3 spots:
- Input 2 * 64 -> 80 bits
- Calculation -> modulo on fractional numbers is never 100% accurate
- Output 80 -> 64 bits
This makes you wonder how our apps were running....
Robert
Small incompatibility with mod operator/function
Posted: Thu Feb 25, 2021 7:04 am
by ArneOrtlinghaus
This is interesting. In my tests I saw that VO sometimes has a higher precision than Dotnet with double/real8, about 3 decimals. This should be due to the use of the 80 bit FPU.
I believe that it needs always quite a lot of work to make business applications work correctly with floating point values . This especially if a database is in between with its own rounding behaviors. Probably converting to the Dotnet type DECIMAL will help in some cases. (decimal)2.0 % (decimal)0.2 gives 0.0.