12

Consider this:

double x,y;
x =120.0;
y = 0.05;

double z= x % y;

I tried this and expected the result to be 0, but it came out 0.04933333.

However,

x =120.0;
y = 0.5;
double z= x % y;

did indeed gave the correct result of 0.

What is happening here?

I tried Math.IEEERemainder(double, double) but it's not returning 0 either. What is going on here?

Also, as an aside, what is the most appropriate way to find remainder in C#?

G S
  • 35,511
  • 22
  • 84
  • 118
  • It would be interesting to know what you're trying to achieve. Using modulus with floating point numbers is never a good idea as the answers already state. – VVS May 25 '09 at 12:53
  • [Related: Python modulo on floats](https://stackoverflow.com/questions/14763722/python-modulo-on-floats) (different language, but the issue -- floating point error -- is the same) – user202729 Jul 27 '18 at 13:12

6 Answers6

16

Because of its storage format, doubles cannot store every values exactly as is is entered or displayed. The human representation of numbers is usually in decimal format, while doubles are based on the dual system.

In a double, 120 is stored precisely because it's an integer value. But 0.05 is not. The double is approximated to the closest number to 0.05 it can represent. 0.5 is a power of 2 (1/2), so it can be stored precisely and you don't get a rounding error.

To have all numbers exactly the same way you enter / display it in the decimal system, use decimal instead.

decimal x, y;
x = 120.0M;
y = 0.05M;

decimal z = x % y;  // z is 0
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • 1
    A `double` is always an exact value. The operation that determined its value may be inexact. `double a = 0.1;` --> `a` has an exact value that may slightly differ than mathematical 0.1. `double b = 0.125;` --> `b` has an exact value that is the same as mathematical 0.125. Still good idea to use `decimal`. – chux - Reinstate Monica Jun 13 '16 at 20:44
  • 4
    "exact value that may slightly differ" == inexact. – Stefan Steinegger Jun 14 '16 at 05:56
  • With integers,,the quotient of 7 divided by 3 is 2 and differs from the mathematical quotient of 2.333.... yet integers are considered exact. Like-wise with FP, 7.0 divided by 3.0 results in a answer near, but not the same as, the value of the mathematically 2.333... In both cases, the operations are not exactly the same as math. In both cases the results are exact. – chux - Reinstate Monica Jun 14 '16 at 13:56
  • 2
    @chux: Every digital value has its resolution. "Exact" in this context means that the value is exactly stored as you **entered** it or as it is **displayed**. Integers are exact values. If you type in 7 (e.g. in a constant in code), it doesn't store 6.999999999999999 behind the scenes. The same for decimals. Doubles are different. Because of its storage format, it cannot exactly store values as they are entered / displayed. – Stefan Steinegger Jun 15 '16 at 06:34
  • 1
    **doubles are never exact values** is an absolute load of hogwash. Given that C# uses IEEE754, this answer could be considerably upgraded. – Bathsheba Jul 13 '17 at 09:12
  • 1
    @Bathsheba: Implementing IEEE754 doesn't help making a double store a decimal value precisely. See my last comment about the discrepancy between entered / displayed values (using the decimal system) and the storage format of a double. If you don't believe what I say, reproduce it yourself using the code in the question. – Stefan Steinegger Jul 19 '17 at 13:24
  • It's the "120 is probably stored lossless" I have issue with. It is *certainly* stored "lossless". – Bathsheba Jul 19 '17 at 13:25
  • Ditto 1/2 which is also "stored lossless" as it's a dyadic rational. – Bathsheba Jul 19 '17 at 13:25
  • @Bathsheba: You are trying very hard to find faults in my answer. You probably find more when you try harder. – Stefan Steinegger Aug 04 '17 at 07:09
11

You could do something like:

double a, b, r;

a = 120;
b = .05;

r = a - Math.floor(a / b) * b;

This should help ;)

Kevin Dungs
  • 1,555
  • 1
  • 13
  • 18
1

http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems can help you understand why you get these "strange" results. There's a particular precision that floating point numbers can have. Just try these queries and have a look at the results:

0.5 in base 2

0.05 in base 2

johv
  • 4,424
  • 3
  • 26
  • 42
Flo
  • 2,738
  • 1
  • 16
  • 12
1

I believe if you tried the same with decimal it would work properly.

configurator
  • 40,828
  • 14
  • 81
  • 115
0

This is what we use.. :)

 public double ModuloOf(double v1, double v2)
    {
        var mult = 0;

        //find number of decimals
        while (v2 % 1 > 0)
        {
            mult++;
            v2 = v2 * 10;
        }

        v1 = v1 * Math.Pow(10, mult);

        var rem = v1 % v2;
        return rem / Math.Pow(10, mult);
    }
0

Modulus should only be used with integer. The remainder come from an euclidean division. With double, you can have unexpected results.

See this article

rockeye
  • 2,765
  • 2
  • 30
  • 44