I was interested in making a type of high-number integer counter relying on the length and accuracy of 4-digit decimal numbers less than 1 when I came across this little slice of misfortune.
Here is the source to see there is no complication on my part:
-- real numbers are flawed! function key() repeat flip() until btnp(4) end b=1 e=10 for i=1,5 do cls() ?"counting "..b.." to "..e.."." key() ?"" for i=b,e,b do ?i end key() b/=10 e/=10 end ?"" color(10) ?"complete!" repeat key() until forever |
Any solutions on how to get the correct numbers here ? And ... does this error extend to LUA or just Pico-8 ?
It extends to all computer representations of floating-point numbers. That cart demonstrates a Floating-Point error. It's not PICO-8's fault. It's not Lua's fault. It's a very common bug in programming, and it's not really preventable afaik.
Here's a section of the Wikipedia article for Floating-point arithmetic.
And here's the same error demonstrated in my browser:
It makes no sense though, @TheV360.
I mean AFAIK decimal numbers just added or subtracted should not be retrieving a wrong value. I wrote code earlier to show you could add and subtract any number of digits, well past trillions:
https://www.lexaloffle.com/bbs/?tid=35715
Granted I had planned to use multiply and divide for these real numbers in my current experiment, but surely it can ... merely add and subtract by .1, .01, .001, and .0001 ?
And I know this error did not occur on the TRS-80 or Apple ][ computer. Because I used floating point numbers then.
Is this some type of encroaching error that has been carried through future OS and never resolved ?
Alright, let's focus for a second then.
Is there a perfect solution or common kludge used today to get past this ?
Now I was trying THIS, and it works, but I don't know how FAR it works, nor is it a good solution as it expects a truncation based on the value itself, which could mess up during complex calculations:
-- real numbers are flawed! function key() repeat flip() until btnp(4) end b=1 e=10 for i=1,5 do cls() ?"counting 0 to "..e.."." key() ?"" for j=0,e,b do n=j n=n+(b/2) n=sub(n,1,i+1) ?n end key() b/=10 e/=10 end ?"" color(10) ?"complete!" repeat key() until forever |
Floating point math is.... iffy. See this great video for a good explanation:
SOLUTION !
Yessiree ! I definitely found a way to fix it.
First off, try this, cause this is weird.
a=0 a=a+.5/10000 ?a |
You get zero as you would expect cause it's smaller than .0001 which is the limitation on variables.
But now try this in immediate mode with the code above:
b=0 if a!=b then print"error" end |
THEY DO NOT MATCH !
So surely one of them is a string, right ? I mean you only have a few variable types, string, table, or number. There is nothing further, right ?
Let's check:
?type(a) ?type(b) |
No, they're both numbers. But ... somehow different. Despite both containing only zero. So ... what's going on here ?
Wow, I wish I knew. :D
But, we can use this to repair our numbers, and we don't need an index to keep track of now. Here is the first code above with solution:
Here is the final code:
-- real numbers are repaired! -- by dw817 function key() repeat flip() until btnp(4) end b=1 e=10 for i=1,5 do cls() ?"counting 0 to "..e.."." key() ?"" for j=0,e,b do n=j+.5/10000 ?n end key() b/=10 e/=10 end ?"" color(10) ?"complete!" repeat key() until forever |
So ... is that all it is ? That single line where you add .5/10000 and ... despite that calculated value by itself clearly being zero it somehow fixes it ? Yep. And that's fine, I'll use that method if that's what it takes to get "accurate" values.
Truth is often stranger than fiction. I think that is happening here.
Now, would someone like to explain WHY this works ? :)
Watching your video, @MBoffin, quite interesting ! I need to know this stuff ...
Eye (O)(-) opening ! I recommend anyone having problems with floating point to watch the video.
The most important thing stated is (1/3) x3, which we understand as humans being the value of 1 is NOT the same as 0.333333333 x3 to a computer which is 0.999999999.
SO ! Therein lies the problem. And, no, I can't see an easy solution around it.
Perhaps future fantasy consoles or even computers for that matter might have something called the "human" factor, optional in math, which looks at a calculation and tries its level best to calculate the way a human would - and more importantly, to return a HUMAN value that makes sense. In this case,
a=1/3 b=a*3 ?b |
Would in fact return the value of 1.
. . .
Still doesn't explain why there can be two variables both with zero and yet ... according to a comparison, they somehow do not match.
To put it simply, print is lying to you. Numbers in pico-8 are 16:16 fixed point numbers(according to the manual). So technically they are not floating point numbers, though the video is still helpful as for how values less than 1 or represented. The 16:16 means that each side of the decimal point is represented by 16 bits or 2 bytes. To see the hexadecimal value of a number use:
tostr(num,true) |
For .0001 this returns 0x0000.0006. This tells us that we can go a bit smaller. However, using
tostr(0x.0001) |
will return 0. This value still exists though.
tostr(0x.0001,true) |
will return 0x0000.0001. And, if we follow your example
tostr(.5/10000,true) |
will return 0x0000.0003.
Here is your demonstration with hexadecimal values added.
Zero zero zero three !
The cake is a lie ! But I LOVE cake. Well, actually like. Pie if it's done right is much better.
Still, PRINT being deceptive ? I would not have expected this. Question. Is it possible to squeeze out a 5th decimal place now since apparently it does indeed exist and PRINT is merely not displaying it ?
Hmm ... this changes so much and explains why zero did not equal zero earlier.
Thanks, @Shoxidizer !
You won't be able to get a whole extra tenths place, there are not enough values smaller than .0001.
The attached program displays how a given value is display, it displayed as a fractional form, the value that its displayed value generates, and how that is displayed.
By the way, you ever try these in the console?
print(.0001) print(.0002) print(.0003) |
One of these is not like the others.
Definitely, @Shoxidizer. .0001 is coming out zero. Makes me wonder how all those great 3D programs execute as well as they do without running into errors.
And your Hexadecimal program above ? Newest gadget to explore. Saved to my folder of favorite offline games. Very interesting to play with. :D
Decimal of string of decimal is especially an area I want to experiment with.
[Please log in to post a comment]