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
Questions About Entity Framework Context Lifetime
Equivalent of Tuple (.Net 4) for .Net Framework 3.5
Removing Hidden Characters from Within Strings
Taking Screenshot of a Webpage Programmatically
Why Gettype Returns System.Int32 Instead of Nullable<Int32>
Can You Access UI Elements from Another Thread? (Get Not Set)
Sqlite .Net Performance, How to Speed Up Things
Newtonsoft.JSON Assembly Package Version Mismatch
Accuracy of Textrenderer.Measuretext Results
Where Are Clr-Defined Methods Like [Delegate].Begininvoke Documented
C# Httpwebrequest the Underlying Connection Was Closed: an Unexpected Error Occurred on a Send
Create Http Post Request and Receive Response Using C# Console Application