Index: flang/lib/Evaluate/real.cpp =================================================================== --- flang/lib/Evaluate/real.cpp +++ flang/lib/Evaluate/real.cpp @@ -406,11 +406,21 @@ ValueWithRealFlags> Real::MOD( const Real &y, Rounding rounding) const { ValueWithRealFlags result; - Real quotient{Divide(y, rounding).AccumulateFlags(result.flags)}; - Real toInt{quotient.ToWholeNumber(common::RoundingMode::ToZero) - .AccumulateFlags(result.flags)}; - Real product{toInt.Multiply(y, rounding).AccumulateFlags(result.flags)}; - result.value = Subtract(product, rounding).AccumulateFlags(result.flags); + auto quotient{Divide(y, rounding)}; + if (quotient.value.IsInfinite() && IsFinite() && y.IsFinite() && + !y.IsZero()) { + // x/y overflowed -- so it must be an integer in this representation and + // the result must be a zero. + if (IsNegative()) { + result.value = Real{}.Negate(); // -0. + } + } else { + Real toInt{quotient.AccumulateFlags(result.flags) + .ToWholeNumber(common::RoundingMode::ToZero) + .AccumulateFlags(result.flags)}; + Real product{toInt.Multiply(y, rounding).AccumulateFlags(result.flags)}; + result.value = Subtract(product, rounding).AccumulateFlags(result.flags); + } return result; } @@ -419,11 +429,21 @@ ValueWithRealFlags> Real::MODULO( const Real &y, Rounding rounding) const { ValueWithRealFlags result; - Real quotient{Divide(y, rounding).AccumulateFlags(result.flags)}; - Real toInt{quotient.ToWholeNumber(common::RoundingMode::Down) - .AccumulateFlags(result.flags)}; - Real product{toInt.Multiply(y, rounding).AccumulateFlags(result.flags)}; - result.value = Subtract(product, rounding).AccumulateFlags(result.flags); + auto quotient{Divide(y, rounding)}; + if (quotient.value.IsInfinite() && IsFinite() && y.IsFinite() && + !y.IsZero()) { + // x/y overflowed -- so it must be an integer in this representation and + // the result must be a zero. + if (y.IsNegative()) { + result.value = Real{}.Negate(); // -0. + } + } else { + Real toInt{quotient.AccumulateFlags(result.flags) + .ToWholeNumber(common::RoundingMode::Down) + .AccumulateFlags(result.flags)}; + Real product{toInt.Multiply(y, rounding).AccumulateFlags(result.flags)}; + result.value = Subtract(product, rounding).AccumulateFlags(result.flags); + } return result; } Index: flang/runtime/numeric.cpp =================================================================== --- flang/runtime/numeric.cpp +++ flang/runtime/numeric.cpp @@ -77,16 +77,19 @@ return mod; } template -inline T RealMod(T x, T p, const char *sourceFile, int sourceLine) { +inline T RealMod(T a, T p, const char *sourceFile, int sourceLine) { if (p == 0) { Terminator{sourceFile, sourceLine}.Crash( IS_MODULO ? "MODULO with P==0" : "MOD with P==0"); } - if constexpr (IS_MODULO) { - return x - std::floor(x / p) * p; - } else { - return x - std::trunc(x / p) * p; + T quotient{a / p}; + if (std::isinf(quotient) && std::isfinite(a) && std::isfinite(p)) { + // a/p overflowed -- so it must be an integer, and the result + // must be a zero of the same sign as one of the operands. + return std::copysign(T{}, IS_MODULO ? p : a); } + T toInt{IS_MODULO ? std::floor(quotient) : std::trunc(quotient)}; + return a - toInt * p; } // RRSPACING (16.9.164) Index: flang/test/Evaluate/fold-mod.f90 =================================================================== --- flang/test/Evaluate/fold-mod.f90 +++ flang/test/Evaluate/fold-mod.f90 @@ -12,6 +12,15 @@ logical, parameter :: test_mod_r4 = mod(8., -5.) == 3. logical, parameter :: test_mod_r5 = mod(-8., -5.) == -3. + logical, parameter :: test_mod_r10a = mod(huge(0.), tiny(0.)) == 0. + logical, parameter :: test_mod_r10b = sign(1., mod(huge(0.), tiny(0.))) == 1. + logical, parameter :: test_mod_r11a = mod(-huge(0.), tiny(0.)) == 0. + logical, parameter :: test_mod_r11b = sign(1., mod(-huge(0.), tiny(0.))) == -1. + logical, parameter :: test_mod_r12a = mod(huge(0.), -tiny(0.)) == 0. + logical, parameter :: test_mod_r12b = sign(1., mod(huge(0.), -tiny(0.))) == 1. + logical, parameter :: test_mod_r13a = mod(huge(0.), tiny(0.)) == 0. + logical, parameter :: test_mod_r13b = sign(1., mod(-huge(0.), -tiny(0.))) == -1. + logical, parameter :: test_modulo_i1 = modulo(8, 5) == 3 logical, parameter :: test_modulo_i2 = modulo(-8, 5) == 2 logical, parameter :: test_modulo_i3 = modulo(8, -5) == -2 @@ -21,4 +30,13 @@ logical, parameter :: test_modulo_r2 = modulo(-8., 5.) == 2. logical, parameter :: test_modulo_r3 = modulo(8., -5.) == -2. logical, parameter :: test_modulo_r4 = modulo(-8., -5.) == -3. + + logical, parameter :: test_modulo_r10a = modulo(huge(0.), tiny(0.)) == 0. + logical, parameter :: test_modulo_r10b = sign(1., modulo(huge(0.), tiny(0.))) == 1. + logical, parameter :: test_modulo_r11a = modulo(-huge(0.), tiny(0.)) == 0. + logical, parameter :: test_modulo_r11b = sign(1., modulo(-huge(0.), tiny(0.))) == 1. + logical, parameter :: test_modulo_r12a = modulo(huge(0.), -tiny(0.)) == 0. + logical, parameter :: test_modulo_r12b = sign(1., modulo(huge(0.), -tiny(0.))) == -1. + logical, parameter :: test_modulo_r13a = modulo(huge(0.), tiny(0.)) == 0. + logical, parameter :: test_modulo_r13b = sign(1., modulo(-huge(0.), -tiny(0.))) == -1. end module