Broadcastblock with Guaranteed Delivery in Tpl Dataflow

Meaning of % operation in C# for the numeric type double

The modulus operator works on floating point values in the same way as it does for integers. So consider a simple example:

4.5 % 2.1

Now, 4.5/2.1 is approximately equal to 2.142857

So, the integer part of the division is 2. Subtract 2*2.1 from 4.5 and you have the remainer, 0.3.

Of course, this process is subject to floating point representability issues so beware – you may see unexpected results. For example, see this question asked here on Stack Overflow: Floating Point Arithmetic - Modulo Operator on Double Type


Is a % b always equivalent to a - b*Math.Round(a/b)?

No it is not. Here is a simple counter example:

static double f(double a, double b)
{
return a - b * Math.Round(a / b);
}

static void Main(string[] args)
{
Console.WriteLine(1.9 % 1.0);
Console.WriteLine(f(1.9, 1.0));
Console.ReadLine();
}

As to the precise details of how the modulus operator is specified you need to refer to the C# specification – earlNameless's answer gives you a link to that.

It is my understanding that a % b is essentially equivalent, modulo floating point precision, to a - b*Math.Truncate(a/b).

Floating Point Arithmetic - Modulo Operator on Double Type

The error comes about because a double can't exactly represent 0.1 -- the closest it can represent is something like 0.100000000000000005551115123126. Now when you divide 1.0 by that it gives you a number slightly less than 10, but again a double can't exactly represent it, so it ends up rounding up to 10. But when you do the mod, it can give you that slightly less than 0.1 remainder.

since 0 = 0.1 mod 0.1, the actual error in the mod is 0.1 - 0.09999999... -- very small.

If you add the result of the % operator to 9 * 0.1, it will give you 1.0 again.

Edit

A bit more detail on the rounding stuff -- particularly as this problem is a good example of the perils of mixed precision.

The way a % b for floating point numbers is usually computed is as a - (b * floor(a/b)). The problem is that it may be done all at once with more internal precision than you'd get with those operations (and rounding the result to a fp number at each stage), so it might give you a different result. One example that a lot of people see is with the Intel x86/x87 hardware is using 80-bit precision for intermediate computations and only 64-bit precision for values in memory. So the value in b in the equation above is coming from memory and is thus a 64-bit fp number that's not quite 0.1 (thank dan04 for the exact value), so when it computes 1.0/0.1 it gets 9.99999999999999944488848768742172978818416595458984375 (rounded to 80 bits). Now if you round that to 64 bits, it would be 10.0, but if you keep the 80 bit internal and do the floor on it, it truncates to 9.0 and thus gets .0999999999999999500399638918679556809365749359130859375 as the final answer.

So in this case, you're seeing a large apparent error because you're using a noncontinuous step function (floor) which means that a very tiny difference in an internal value can push you over the step. But since mod is itself a noncontinuous step function thats to be expected and the real error here is 0.1-0.0999... as 0.1 is the discontinuous point in the range of the mod function.

C# modulo is giving me the wrong asnwer?

The problem is the floating-point arithmetics and its inability to represent all decimal numbers precisely. A simple test reveals the differences:

decimal type:

Console.WriteLine(180m % 3.6m); // 0.0

float type:

Console.WriteLine(180f % 3.6f); // 4.768372E-06

double type:

Console.WriteLine(180d % 3.6d); // 3.6

The modulus operator (%) doesn't work for huge numbers

Use BigInteger. int or even unsigned long is way too small to hold the product. And calculating integer values with double is also problematic.

BigInteger has a static method ModPow made exactly for your purpose:

int N = 10379
int S1 = 3701;
int d = 37;
BigInteger T1 = BigInteger.ModPow(S1, d, N); // 7770

C# Bug in Modulo Operator %

Math.Pow(64, 1.0 / 3.0) returns 3.9999999999999996.

This gets rounded to 4 when displayed.

Taking it modulo 1 returns 0.99999999999999956, which is similarly rounded to 1 when displayed.

You can see the true values by adding .ToString("R")

Modulo C# is not producing expected value

Can you try using decimal instead of double ?



Related Topics



Leave a reply



Submit