[Oberon] Wrong results of selected REAL multiplications
Hans Klaver
hklaver at dds.nl
Sun Oct 8 22:17:39 CEST 2023
Hi all,
Recently when looking into seemingly wrong output of my code for Texts.WriteReal and Texts.WriteRealFix I discovered that Project Oberon RISC5 floating point multiplication gives wrong results for certain selected values.
Specifically when multiplying a number containing the digits of a whole power of 2 by a whole power of 10 sometimes results in *half* the value of the right result; this only occurs when the result is (the REAL representation of) an exact whole power of 2; but puzzlingly in some of these cases the error is not produced.
E.g.:
100.0 * 2.56 results in 1.280000E+02 = 128.0 (encoded ('raw') hexadecimal integer value: 43000000H)
The right result of this multiplication (2.560000E+02) in hex is 43800000H
1.0E5 * 1.31072 results in 6.553600E+04 = 65536.0 (encoded ('raw') hexadecimal integer value: 47800000H)
The right result of this multiplication (131072.0) in hex is 48000000H
1.0E6 * 1.048576 results in 5.242880E+05 = 524288.0 (encoded ('raw') hexadecimal integer value: 49000000H)
The right result of this multiplication (1048576.0) in hex is 49800000H
But in the following similar case the right result is produced:
1.0E3 * 8.192 results in 8.192000 = 8192.0 (encoded ('raw') hexadecimal integer value: 46000000H)
You can verify the integer encodings for IEEE 754 floating point values on the following web page:
https://float.exposed (click on 'float' (not on 'double'), paste the hex value (without trailing H) into the field 'Raw Hexadecimal Integer Value' and then press Enter).
That these wrong results are not explained by wrong output of Texts.WriteReal is indicated by the hexadecimal encoded results, and also by the fact that the output of Texts.WriteReal for slightly different values is correct.
E.g.:
1000.0 * 2.56 results in 2.560000E+03 = 2560.0 (encoded ('raw') hexadecimal integer value: 45200000H)
1.0E6 * 1.048577 results in 1.048577E+06 = 1048577.0 (encoded ('raw') hexadecimal integer value: 49800008H)
I compiled and ran the procedure below to test this on Peter de Wachter's RISC emulator.
Could someone compile and run this test module on a hardware RISC5 FPGA board to verify the results?
Is this a known issue? Does anyone have an explanation?
Hans Klaver
MODULE TestRealMul;
IMPORT Texts, Oberon;
VAR W: Texts.Writer;
PROCEDURE WriteRealHex* (VAR W: Texts.Writer; x: REAL);
(* Write the encoded ('raw') hexadecimal INTEGER value of a REAL.
Verify on https://float.exposed *)
BEGIN
Texts.WriteHex(W, ORD(x)); Texts.Write(W, "H")
END WriteRealHex;
PROCEDURE Do*;
BEGIN
Texts.WriteString(W, "1.0E6 * 1.048575 = ");
Texts.WriteReal(W, 1.0E6 * 1.048575, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E6 * 1.048576 = ");
Texts.WriteReal(W, 1.0E6 * 1.048576, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E6 * 1.048576 = ");
Texts.WriteRealHex(W, 1.0E6 * 1.048576); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E6 * 1.048577 = ");
Texts.WriteReal(W, 1.0E6 * 1.048577, 16); Texts.WriteLn(W); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E6 * 2.097152 = ");
Texts.WriteReal(W, 1.0E6 * 2.097152, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E6 * 4.194304 = ");
Texts.WriteReal(W, 1.0E6 * 4.194304, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E5 * 1.31072 = ");
Texts.WriteReal(W, 1.0E5 * 1.31072, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E4 * 3.2768 = ");
Texts.WriteReal(W, 1.0E4 * 3.2768, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E4 * 1.6384 = ");
Texts.WriteReal(W, 1.0E4 * 1.6384, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E3 * 8.192 = ");
Texts.WriteReal(W, 1.0E3 * 8.192, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E3 * 4.096 = ");
Texts.WriteReal(W, 1.0E3 * 4.096, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E3 * 2.048 = ");
Texts.WriteReal(W, 1.0E3 * 2.048, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E3 * 1.024 = ");
Texts.WriteReal(W, 1.0E3 * 1.024, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E2 * 2.56 = ");
Texts.WriteReal(W, 1.0E2 * 2.56, 16); Texts.WriteLn(W);
Texts.WriteString(W, "100.0 * 2.56 = ");
Texts.WriteReal(W, 100.0 * 2.56, 16); Texts.WriteLn(W);
Texts.WriteString(W, "100.0 * 2.56 = ");
Texts.WriteRealHex(W, 100.0 * 2.56); Texts.WriteLn(W);
Texts.WriteString(W, "1000.0 * 2.56 = ");
Texts.WriteReal(W, 1000.0 * 2.56, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E2 * 1.28 = ");
Texts.WriteReal(W, 1.0E2 * 1.28, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E1 * 6.4 = ");
Texts.WriteReal(W, 1.0E1 * 6.4, 16); Texts.WriteLn(W);
Texts.WriteString(W, "1.0E1 * 3.2 = ");
Texts.WriteReal(W, 1.0E1 * 3.2, 16); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END Do;
BEGIN Texts.OpenWriter(W)
END TestRealMul.Do
System.Free TestRealMul ~
More information about the Oberon
mailing list