Small incompatibility with mod operator/function

This forum is meant for questions and discussions about the X# language and tools
User avatar
ArneOrtlinghaus
Posts: 384
Joined: Tue Nov 10, 2015 7:48 am
Location: Italy

Small incompatibility with mod operator/function

Post 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
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Small incompatibility with mod operator/function

Post 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?
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
User avatar
ArneOrtlinghaus
Posts: 384
Joined: Tue Nov 10, 2015 7:48 am
Location: Italy

Small incompatibility with mod operator/function

Post 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
User avatar
ArneOrtlinghaus
Posts: 384
Joined: Tue Nov 10, 2015 7:48 am
Location: Italy

Small incompatibility with mod operator/function

Post 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
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Small incompatibility with mod operator/function

Post 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?
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
User avatar
ArneOrtlinghaus
Posts: 384
Joined: Tue Nov 10, 2015 7:48 am
Location: Italy

Small incompatibility with mod operator/function

Post 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
User avatar
ArneOrtlinghaus
Posts: 384
Joined: Tue Nov 10, 2015 7:48 am
Location: Italy

Small incompatibility with mod operator/function

Post 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
User avatar
ArneOrtlinghaus
Posts: 384
Joined: Tue Nov 10, 2015 7:48 am
Location: Italy

Small incompatibility with mod operator/function

Post by ArneOrtlinghaus »

User avatar
robert
Posts: 4225
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Small incompatibility with mod operator/function

Post 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
XSharp Development Team
The Netherlands
robert@xsharp.eu
User avatar
ArneOrtlinghaus
Posts: 384
Joined: Tue Nov 10, 2015 7:48 am
Location: Italy

Small incompatibility with mod operator/function

Post 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.
Post Reply