The value of the operation "%" in C # for the numeric type double

I recently discovered that the C # % operator is applicable to double. I tried something, and eventually came up with this test:

 class Program { static void test(double a, double b) { if (a % b != a - b * Math.Truncate(a / b)) { Console.WriteLine(a + ", " + b); } } static void Main(string[] args) { test(2.5, 7); test(-6.7, -3); test(8.7, 4); //... } } 

Everything in this test works. Is a % b always equivalent to a - b*Math.Round(a/b) ? If not, explain to me how this operator works.

EDIT: Responding to James L, I understand that this is a modulo operator and all that. I am only curious how this works with double integers, which I understand.

+5
source share
4 answers

The module operator works with floating point values ​​in the same way as for integers. So, consider a simple example:

 4.5 % 2.1 

Now 4.5 / 2.1 is approximately 2.142857

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

Of course, this process is subject to floating-point representation problems, so be careful - you may see unexpected results. For example, see This Question Asked Here in the Stack Overflow Section: Floating-Point Arithmetic - Modulo Operator for a Double Type


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

No, it is not. Here is a simple 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(); } 

Regarding the exact details of how the module operator is specified, you need to refer to the C # specification - earlNameeless answer gives you a link to this.

As far as I understand, a % b is essentially equivalent modulo floating point precision to a - b*Math.Truncate(a/b) .

+6
source

From the C # Language Specification page:

Floating point remainder:

 float operator %(float x, float y); double operator %(double x, double y); 

The following table lists the results of all possible combinations of nonzero finite values, zeros, infinities, and NaN. In the table, x and y are positive final values. z is the result of x% y and is calculated as x - n * y, rounded to the nearest representable value, where n is the largest integer that is less than or equal to x / y. This method of calculating the remainder is similar to the method used for integer operands, but differs from the definition of IEC 60559 (in which n is the integer closest to x / y).

+4
source

From the MSDN page :

The module operator (%) calculates the remainder after dividing its first operand by the second. All numeric types have a predefined module operators.

and

Note the rounding errors associated with the double type.

+2
source

A search for the phrase “modulo a C # floating point” results in a fairly large number of entries in the stack overflow, most of which explain well how floating point precision complicates the situation. I did not recognize a single suggestion regarding a simple practical way to handle this. For my own purposes, I came up with the following modulo function:

 public static double modulo( double a, double b, double num_sig_digits = 14 ) { double int_closest_to_ratio , abs_val_of_residue ; if ( double.IsNaN( a ) || double.IsNaN( b ) || 0 == b ) { throw new Exception( "function modulo called with a or b == NaN or b == 0" ); } if ( b == Math.Floor( b ) ) { return (a % b); } else { int_closest_to_ratio = Math.Round( a / b ); abs_val_of_residue = Math.Abs( a - int_closest_to_ratio * b ); if ( abs_val_of_residue < Math.Pow( 10.0, -num_sig_digits ) ) { return 0.0; } else { return abs_val_of_residue * Math.Sign( a ); } } } 

The following are some sample results:

modulo (0.5, 0.1, 17) = 0

modulo (0.5, -0.1, 16) = 0

modulo (-0.5, 0,1, 15) = 0

modulo (-0.5, -0.1, 14) = 0

modulo (0.52, 0.1, 16) = 0.02

modulo (0.53, -0.1, 15) = 0.03

modulo (-0.54, 0.1, 14) = -0.04

modulo (-0.55, -0.1, 13) = -0.05

modulo (2.5, 1.01, 17) = 0.48

modulo (2.5, -1 0.01, 16) = 0.48

modulo (-2.5, 1.01, 15) = -0.48

modulo (-2.5, -1.01, 14) = -0.48

modulo (0.599999999999977, 0,1, 16) = 2,35367281220533E -1 4

modulo (0.599999999999977, 0,1, 15) = 2,35367281220533E -1 4

modulo (0.599999999999977, 0,1, 14) = 2,35367281220533E -1 4

modulo (0.599999999999977, 0,1, 13) = 0

modulo (0.599999999999977, 0,1, 12) = 0

0
source

Source: https://habr.com/ru/post/1380917/


All Articles