zathras / jrpn

JRPN - A Calculator Simulator Inspired by the HP-16C "Computer Scientist" Calculator and the HP-15C Scientific Calculator
https://jrpn.jovial.com/
Other
65 stars 8 forks source link

Rounding inaccuracy and different behavior to original 15C #74

Closed pane closed 9 months ago

pane commented 9 months ago

Hallo Bill,

Very nice and useful emulators! A lot of work and a big improvement in last versions, thank you.

KR Pavel

Here is my finding of the difference from my HP 15C CE which might not be the bug since you stated results could be different. But in some cases it can generate wrong result (two 1/x 1/x should return the same number or an error if zero) and this I would call the bug.

JRPN 16C or 15C? Assume both 16C and 15C, tested on 15C only

Describe the bug Rounding error beyond 10th decimal place

Debug Log Slightly different keystroke examples to the program listed here. The Debug Log is attached at the end of the post.

To Reproduce Please run this program: Program produced by JRPN 15C. Character encoding: UTF-8 Generated 2024-1-27 18:31 Central European Standard Time.

000 { } 001 { 42 21 9 } f LBL 9 002 { 4 } 4 003 { 36 } ENTER 004 { 3 } 3 005 { 10 } / 006 { 1 } 1 007 { 30 } - 008 { 3 } 3 009 { 20 } * 010 { 1 } 1 011 { 30 } - 012 { 44 1 } STO 1 013 { 42 31 } f PSE 014 { 9 } 9 015 { 48 } . 016 { 9 } 9 017 { 9 } 9 018 { 9 } 9 019 { 9 } 9 020 { 9 } 9 021 { 9 } 9 022 { 26 } EEX 023 { 1 } 1 024 { 0 } 0 025 { 16 } CHS 026 { 40 } + 027 { 42 31 } f PSE 028 { 36 } ENTER 029 { 15 } 1/x 030 { 15 } 1/x 031 { 30 } - 032 { 31 } R/S

End.

Expected behavior It should give 0

Platform: Windows

Additional context More subtraction of few first significant digits generate some tail numbers probably due to floating point approximation.

Debug Log copy {"version":1,"modelName":"15C","settings":{"menuEnabled":true,"windowEnabled":false,"longNumbers":1,"euroComma":false,"showAccelerators":true,"systemOverlaysDisabled":false,"orientation":0,"keyFeedback":0},"displayMode":"s9","integerSignMode":"2","wordSize":56,"stack":["9999995875963","0","0","0"],"lastX":"98000000026973","flags":[false,false,false,false,false,false,false,false,false,false],"memory":{"storage":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000099999999717990999999997179900000000000000000000000000000","program":{"lines":0,"currentLine":0,"returnStack":[0,0,0,0,0,0,0],"returnStackPos":-1},"I":"0"},"debugLog":{"initialState":{"version":1,"modelName":"15C","settings":{"menuEnabled":true,"windowEnabled":false,"longNumbers":1,"euroComma":false,"showAccelerators":true,"systemOverlaysDisabled":false,"orientation":0,"keyFeedback":0},"displayMode":"s9","integerSignMode":"2","wordSize":56,"stack":["99999999717990","0","0","0"],"lastX":"1000000000000","flags":[false,false,false,false,false,false,false,false,false,false],"memory":{"storage":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","program":{"lines":0,"currentLine":0,"returnStack":[0,0,0,0,0,0,0],"returnStackPos":-1},"I":"0"},"numRegisters":20,"resultMatrix":0,"matrices":[{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null}],"lastRandom":0.9669274102035026},"keys":[-2,124,4,125,3,25,1,134,3,97,1,134,146,2,9,231,9,9,9,78,1,0,20,237,9,231,9,9,7,1,7,78,1,4,20,237,18,18,4,125,3,25,1,134,3,97,1,134,146,3,9,231,9,9,9,9,9,9,7,78,1,0,20,237,1,231,7,0,0,0,0,0,0,8,78,1,8,134,237,-2,127,134,182,3,9,231,9,9,9,9,9,9,7,78,1,0,20,237,1,231,7,0,0,0,0,0,0,8,78,1,8,20,237,125,18,18,134]},"endDisplay":" 9.999995875E-37","numRegisters":20,"resultMatrix":0,"matrices":[{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null},{"columns":0,"values":[],"rowSwaps":null}],"lastRandom":0.9669274102035026}

zathras commented 9 months ago

Interesting. The divergence is happening at the addition operation on line 26...

At line 13, both have -1e-9 At line 27, the real calculator has -1e-16, and simulator has -7.169999999E-17 After two reciprocal operations, the simulator has -7.169999997E-17

It's a little counter-intuitive, but the simulator behavior isn't unexpected here. It's a result of going from decimal to binary, doing the operation, and then rounding back to decimal at every step.

A different strategy would have been to maintain binary floating point internally and display as decimal, but that would lead to other odd behaviors (like something that displays as 0 but is actually too small to display, like 1E-200).

To get the exact 15C behavior, I'd have to do all the internal math in decimal. That would mean implementing all the mathematical operations myself (or copying/adapting someone else's implementations). That would be a moderately significant undertaking. Kind of fun, mind you -- actually implementing tan and sqrt and y^x and all the rest from the ground up would be a fun project; I might even give it a whirl some day. I captured this in https://github.com/zathras/jrpn/issues/76.

But for now, counter-intuitive though it be, this is the intended behavior.

zathras commented 9 months ago

Oh, by the way, on the real 15C, -7.169999999E-17 1/x 1/x yields 7.169999997E-17, just like in the simulator. Representing real numbers in a fixed-size representation (decimal or binary) leads to fun results like this.

pane commented 9 months ago

Indeed, really interesting! I did not try this on real 15C, thanks for pointing this quirk out. It seams ..6999 makes the trouble. KR P P.S. Very interesting read about your parents.