Searching with the phrase "modulo floating point c#" brings up quite a few entries in Stack Overflow, most of them explaining nicely how floating point precision complicates things. I did not recognize any suggestion for a simple practical way to handle that. What I came up with for my own purposes is 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 );
}
}
}
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.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-14
modulo( 0.599999999999977, 0.1, 15 ) = 2.35367281220533E-14
modulo( 0.599999999999977, 0.1, 14 ) = 2.35367281220533E-14
modulo( 0.599999999999977, 0.1, 13 ) = 0
modulo( 0.599999999999977, 0.1, 12 ) = 0