diff options
Diffstat (limited to 'src/Execution/Runtime.php')
| -rw-r--r-- | src/Execution/Runtime.php | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/src/Execution/Runtime.php b/src/Execution/Runtime.php index 10bed7c..98893d0 100644 --- a/src/Execution/Runtime.php +++ b/src/Execution/Runtime.php @@ -599,7 +599,9 @@ final class Runtime { $c2 = $this->stack->popFloat(); $c1 = $this->stack->popFloat(); - $this->stack->pushValue($c1 * ($c2 < 0 ? -1 : 1)); + $c1Sign = self::getFloatSign($c1); + $c2Sign = self::getFloatSign($c2); + $this->stack->pushValue($c1Sign === $c2Sign ? $c1 : -$c1); } private function execInstrNumericF32DemoteF64(Instrs\Numeric\F32DemoteF64 $instr): void @@ -793,7 +795,9 @@ final class Runtime { $c2 = $this->stack->popFloat(); $c1 = $this->stack->popFloat(); - $this->stack->pushValue($c1 * ($c2 < 0 ? -1 : 1)); + $c1Sign = self::getFloatSign($c1); + $c2Sign = self::getFloatSign($c2); + $this->stack->pushValue($c1Sign === $c2Sign ? $c1 : -$c1); } private function execInstrNumericF64Div(Instrs\Numeric\F64Div $instr): void @@ -2606,4 +2610,18 @@ final class Runtime } return (int)$result; } + + private static function getFloatSign(float $p): int + { + if (is_nan($p)) { + $n = BinaryConversion::reinterpretF64AsI64($p); + // The MSB is the sign bit. + return (($n >> 63) & 1) === 1 ? -1 : 1; + } elseif ($p !== 0.0) { + return $p < 0.0 ? -1 : 1; + } else { + // Comparison with 0 does not work for -0.0. + return fdiv(1, $p) < 0.0 ? -1 : 1; + } + } } |
