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