зеркало из https://github.com/microsoft/Power-Fx.git
Fix overflow of Mod_Float for large number (#1522)
Fix issue: https://github.com/microsoft/Power-Fx/issues/1367 Problem this PR fix: Start from 1e+16 to 1e+20, current mod_float return 0 for most of the case (mostly wrong value). And overflow from 1e+21 or higher. This PR use C# % function to do mod for the wrong/overflow issues. Note on PA (Need to fix as well): mod result is always 0 from 1e18 (mod 123). So, it shared the same problem. mod result is wrong for > 1e17. It did not return overflow error for 1e306 but return 0 (wrong value). --------- Co-authored-by: Carlos Figueira <carlosff@microsoft.com>
This commit is contained in:
Родитель
ed759c95ad
Коммит
a8805417aa
|
@ -760,20 +760,14 @@ namespace Microsoft.PowerFx.Functions
|
|||
return CommonErrors.DivByZeroError(irContext);
|
||||
}
|
||||
|
||||
// r = a – N × floor(a/b)
|
||||
double q = Math.Floor(arg0 / arg1);
|
||||
if (IsInvalidDouble(q))
|
||||
{
|
||||
return CommonErrors.OverflowError(irContext);
|
||||
}
|
||||
double result = arg0 % arg1;
|
||||
|
||||
double result = arg0 - (arg1 * ((long)q));
|
||||
|
||||
// We validate the reminder is in a valid range.
|
||||
// This is mainly to support very large numbers (like 1E+308) where the calculation could be incorrect
|
||||
if (result < -Math.Abs(arg1) || result > Math.Abs(arg1))
|
||||
// % result has the same sign with dividend.
|
||||
// Using the following fomular to have the sign of mod result is the same as divisor as in Excel and PA Mod.
|
||||
// If result has different sign with divisor, plus result with divisor to flip the sign to be the same with divisor.
|
||||
if (Math.Sign(result) * Math.Sign(arg1) == -1)
|
||||
{
|
||||
return CommonErrors.OverflowError(irContext);
|
||||
result = result + arg1;
|
||||
}
|
||||
|
||||
return new NumberValue(irContext, result);
|
||||
|
@ -783,25 +777,22 @@ namespace Microsoft.PowerFx.Functions
|
|||
{
|
||||
decimal arg0 = arg0dv.Value;
|
||||
decimal arg1 = arg1dv.Value;
|
||||
decimal q;
|
||||
|
||||
|
||||
// Both decimal zero and negative zero will satisfy this test
|
||||
if (arg1 == 0m)
|
||||
{
|
||||
return CommonErrors.DivByZeroError(irContext);
|
||||
}
|
||||
|
||||
// r = a – N × floor(a/b)
|
||||
try
|
||||
{
|
||||
q = decimal.Floor(arg0 / arg1);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
return CommonErrors.OverflowError(irContext);
|
||||
}
|
||||
decimal result = arg0 % arg1;
|
||||
|
||||
decimal result = arg0 - (arg1 * q);
|
||||
// % result has the same sign with dividend.
|
||||
// Using the following fomular to have the sign of mod result is the same as divisor as in Excel and PA Mod.
|
||||
// If result has different sign with divisor, plus result with divisor to flip the sign to be the same with divisor.
|
||||
if (Math.Sign(result) * Math.Sign(arg1) == -1)
|
||||
{
|
||||
result = result + arg1;
|
||||
}
|
||||
|
||||
return new DecimalValue(irContext, result);
|
||||
}
|
||||
|
|
|
@ -410,9 +410,6 @@ Error({Kind:ErrorKind.Div0})
|
|||
>> Mod(2,0)
|
||||
Error({Kind:ErrorKind.Div0})
|
||||
|
||||
>> Mod(10^200,-10^-200)
|
||||
Error({Kind:ErrorKind.Numeric})
|
||||
|
||||
>> Mod(Sqrt(-1),If(Char(0)="a",1))
|
||||
Error(Table({Kind:ErrorKind.Numeric},{Kind:ErrorKind.InvalidArgument}))
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ Error({Kind:ErrorKind.Numeric})
|
|||
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
>> Mod(1E+300,1E-20)
|
||||
Error({Kind:ErrorKind.Numeric})
|
||||
6.0682893566359166E-21
|
||||
|
||||
>> Dec2Hex([1,1e-45,1e45,2])
|
||||
Table({Value:"1"},{Value:"0"},{Value:Error({Kind:ErrorKind.Numeric})},{Value:"2"})
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#SETUP: disable:NumberIsFloat
|
||||
|
||||
>> Mod(1E+27, 3)
|
||||
1
|
||||
|
||||
>> Mod(-1E+27, -3)
|
||||
-1
|
||||
|
||||
>> Mod(1E+19, 123)
|
||||
37
|
||||
|
||||
>> Mod(1.2345E+26, 67.89)
|
||||
0.81
|
||||
|
||||
>> Mod(79228162514264337593543.1234, 3.5678)
|
||||
1.3776
|
||||
|
||||
>> Mod(79228162514264337593543950335, 123)
|
||||
99
|
|
@ -0,0 +1,35 @@
|
|||
#SETUP: NumberIsFloat
|
||||
|
||||
>> Mod(1E+307, 3)
|
||||
1
|
||||
|
||||
>> Mod(1E+307, -3)
|
||||
-2
|
||||
|
||||
>> Mod(-1E+307, 3)
|
||||
2
|
||||
|
||||
>> Mod(-1E+307, -3)
|
||||
-1
|
||||
|
||||
>> Mod(1.7976931348623157E+300, 3)
|
||||
1
|
||||
|
||||
>> Mod(1.2345E+260, 67.89)
|
||||
41.28195726574958
|
||||
|
||||
>> Mod(1E+13, 123)
|
||||
16
|
||||
|
||||
>> Mod(1E+18, 123)
|
||||
16
|
||||
|
||||
>> Mod(1E+18, -123)
|
||||
-107
|
||||
|
||||
// Not exact result due to floating point semantics
|
||||
>> Mod(10^200,-10^-200)
|
||||
-5.8180083079168396E-201
|
||||
|
||||
>> Mod(1E+400, 3)
|
||||
Errors: Error 4-10: Numeric value is too large.|Error 0-14: The function 'Mod' has some invalid arguments.|Error 4-10: Invalid argument type (Error). Expecting a Number value instead.
|
Загрузка…
Ссылка в новой задаче