+yetanothertroll Posted June 23 Share Posted June 23 2 hours ago, ClausB said: When I worked at New Dimensions in Computing in 1981 they asked me to find out why their accounting program was dropping pennies. It was in MS BASIC for CP/M on a Vector Graphic S100 system. The floating point variables were in dollars, so 0.01 dollars was not exact because of the binary representation. I added some rounding to fix it. Also sales tax percentage, 4% or 0.04, was not exact plus there were rounding rules specified in the law. Atari's BCD representation would not have lost pennies, nor would have MS if the variables had been defined in cents instead of dollars. That's why IBM and other mainframe manufacturers loved them some BCD, as did bean counters everywhere, although scaled 64 bit integer data types like M$'s Currency or bignum-like Decimal fit the bill as well. There are also modern "densely packed decimal" schemes to store three decimal digits in every ten bits to ease the space inefficiency pain. 1 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted June 24 Share Posted June 24 On 6/22/2024 at 11:54 PM, thorfdbg said: "different" is an euphemism. "Many more" is more appropriate. It has serious rounding issues. Is it because of the BCD or because of the six bytes, like how everyone uses 64 bit double even when 32 bit float would often do Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted June 26 Share Posted June 26 On 6/24/2024 at 10:32 PM, yetanothertroll said: Is it because of the BCD or because of the six bytes, like how everyone uses 64 bit double even when 32 bit float would often do Its because it arithmetic to the basis of 100. The rounding loss a number format creates depends on this basis, and larger bases have larger losses. With its base-100 arithmetic, the math pack performs considerably worse than binary implementations. Six bytes for floating point are fine. IEEE single precision only takes four, which is quite sufficient for many elementary needs. 2 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted June 26 Share Posted June 26 3 hours ago, thorfdbg said: Its because it arithmetic to the basis of 100. The rounding loss a number format creates depends on this basis, and larger bases have larger losses. With its base-100 arithmetic, the math pack performs considerably worse than binary implementations. Six bytes for floating point are fine. IEEE single precision only takes four, which is quite sufficient for many elementary needs. I wonder if Atari went with BCD because early electronic calculators did, and it wouldn't do for a $500-1000 home computer to have a smaller range or show different results for simple calculations than dad's fourbanger http://datamath.org/EarlyArchitecture.htm Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 27 Share Posted June 27 The story I read is they grabbed what was used off the shelf at low or no cost rather than paying for or developing a better one. 1 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted June 27 Share Posted June 27 (edited) On 6/22/2024 at 5:15 AM, TGB1718 said: I'm writing a program that will be running on a vanilla 800XL that's extensively using floating point numbers, the data will be saved to disk. [...] Depending on what you're doing with the data, this might be of interest to you, especially if you later want to play with 6 000, 6 000 000, or 6 000 000 000+ numbers instead of merely 600 or so https://www.johndcook.com/blog/skewness_kurtosis/ Edit: I dun goofed. Even with the above code, expect trouble after processing only 999 999 999 numbers or so even with the OS-B mathpack. There are likely to be other gotchas Edited June 27 by yetanothertroll Atari floating point, how does it work Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted June 27 Author Share Posted June 27 (edited) 6 hours ago, yetanothertroll said: Edit: I dun goofed. Even with the above code, expect trouble after processing only 999 999 999 numbers or so even with the OS-B mathpack. There are likely to be other gotchas Yes, I spotted that, I'm only interested in printable numbers without the "E", and this is what I found that the conversion process does with large numbers. look what happens if you exceed that number of characters (it's not the value, it's the number of characters) it does exactly the same thing with 9999999.99 and then make it 99999999.99 this is ok A=1234567.99 ?A 1234567.99 but add another number and it truncates the last character A=12345678.99 ?A 12345678.9 I wasn't aware it did this, it's not a limit of the value, but the floating point package is used to convert numbers to strings for display, and I think that's where the limit comes from, the output buffer is only big enough to accommodate 10 characters including the "." Luckily that's good enough for what I'm doing EDIT: just checked and the FP package uses BASIC's line buffer which is 128 bytes long at $580 to $5FF so it's not a buffer limit, just probably the max characters the FP package will process. Edited June 27 by TGB1718 Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted June 27 Share Posted June 27 20 hours ago, yetanothertroll said: I wonder if Atari went with BCD because early electronic calculators did, and it wouldn't do for a $500-1000 home computer to have a smaller range or show different results for simple calculations than dad's fourbanger Atari Basic the math pack is part of was a quick rough job, and given the time it was developed in, it is actually quite good. But, apparently, mathematics was not quite in focus here. Also multiplication and division would have been easier in binary than in BCD. 1 Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted June 27 Share Posted June 27 9 hours ago, TGB1718 said: this is ok A=1234567.99 ?A 1234567.99 but add another number and it truncates the last character A=12345678.99 ?A 12345678.9 This is the result of the base 100 computation I was talking about. The mathpack can only adjust/shifts numbers by bytes, and thus pairs of digits. It adds to the rather large rounding loss of the mathpack implementation. 1 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted June 27 Share Posted June 27 9 hours ago, TGB1718 said: Yes, I spotted that, I'm only interested in printable numbers without the "E", and this is what I found that the conversion process does with large numbers. look what happens if you exceed that number of characters (it's not the value, it's the number of characters) it does exactly the same thing with 9999999.99 and then make it 99999999.99 this is ok A=1234567.99 ?A 1234567.99 but add another number and it truncates the last character A=12345678.99 ?A 12345678.9 I wasn't aware it did this, it's not a limit of the value, but the floating point package is used to convert numbers to strings for display, and I think that's where the limit comes from, the output buffer is only big enough to accommodate 10 characters including the "." Luckily that's good enough for what I'm doing EDIT: just checked and the FP package uses BASIC's line buffer which is 128 bytes long at $580 to $5FF so it's not a buffer limit, just probably the max characters the FP package will process. Part of it is that I've gotten a little too used to dmsc's FastBasic, which behaves differently than Atari BASIC in some ways. FB seems to be no better than BASIC at converting string to floating point, still losing that pesky tenth digit even when there's room for it in memory, but it can do accurate arithmetic involving the tenth digit in some circumstances BASIC doesn't, test.rom test.bas Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted June 27 Share Posted June 27 59 minutes ago, thorfdbg said: This is the result of the base 100 computation I was talking about. The mathpack can only adjust/shifts numbers by bytes, and thus pairs of digits. It adds to the rather large rounding loss of the mathpack implementation. Doesn't multiplying or dividing by 10 require shifting by nybble? There's nybble shifting going on somewhere, somehow. I modified the FastBasic program to divide then multiply by 10, ' Program FPTest Dim Z%(2) Do Input "Number or Q to quit? "; X$ If X$ = "Q" Then Exit Print X$; " entered" Z%(0) = Val(X$) Print Z%(0); ": "; @FPDump Adr(Z%) + 0 Z%(1) = Z%(0) / 10.0 Print Z%(1); ": "; @FPDump Adr(Z%) + 6 Z%(2) = Z%(0) * 10.0 Print Z%(2); ": "; @FPDump Adr(Z%) + 12 Loop Print Print "OK" Get ZZ End Proc FPDump Za Data Hex() Byte ROM = "0123456789ABCDEF" ' Hex dump Print "$"; For i = 0 to 5 If i Then Print "'"; j = Peek(Za + i) Print Chr$(Hex(1 + (j / 16))); ' So which way of doing this is better? Print Chr$(Hex(1 + (j & 15))); Next i Print ' Quick and dirty Str$(), sort of Print " = "; If (Peek(Za) & 128) Then Print "-"; For i = 1 to 5 j = Peek(Za + i) Print $(&Hex)[1 + (j / 16), 1]; ' I have absolutely no idea whatsoever! Print $(&Hex)[1 + (j & 15), 1]; If i = 1 Then Print "."; Next i Print " * 100 ^ "; (127 & Peek(Za)) - 64 EndProc test.rom test.bas Quote Link to comment Share on other sites More sharing options...
phaeron Posted June 28 Share Posted June 28 That's the AFP issue I had mentioned earlier. It only shifts in up to 9 digits when converting ATASCII to floating point, even in cases where a 10th digit would fit. 1 1 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted June 28 Share Posted June 28 (edited) 28 minutes ago, phaeron said: That's the AFP issue I had mentioned earlier. It only shifts in up to 9 digits when converting ATASCII to floating point, even in cases where a 10th digit would fit. It's even worse than that. Even FP to ATASCII is goofy in Atari BASIC, even with integer values, while under the hood simple arithmetic appears to work, 10 V=VAL("9999999989") 15 W=V:? W;" ";V;" ";ABS(W-V) 20 X=W+1 30 Y=X-W 40 Z=Y-1 45 PRINT W-V;" "; 50 PRINT W;" ";X;" ";Y;" ";Z 60 IF Z<>0 THEN 90 70 W=X 80 GOTO 20 90 END EDIT: ...well, up to a point, anyway. My brain hurts Edited June 28 by yetanothertroll Specialist: It will have to come out. Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted June 28 Share Posted June 28 10 hours ago, yetanothertroll said: Doesn't multiplying or dividing by 10 require shifting by nybble? It does, but the math pack does not normalize numbers by nibbles, but only by bytes. Normalizing here means that the exponents of two numbers to add or subtract are identical. 1 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted July 1 Share Posted July 1 On 6/28/2024 at 12:19 AM, thorfdbg said: It does, but the math pack does not normalize numbers by nibbles, but only by bytes. Normalizing here means that the exponents of two numbers to add or subtract are identical. I'm not sure why the base 100 thing is so bad. I've done base 100 myself when writing my own bignum code in various languages or even base 1'000'000'000 when attempting a bignum package in 8-bit Logo. I think the issues are, five bytes for the mantissa aren't a lot, and Atari went and burned the 0.9 alpha to the production OS ROMs. Maybe the 1.0 would have had ten digit conversion routines and cleaned up the rest, who knows https://atariwiki.org/wiki/Wiki.jsp?page=Atari BASIC Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted July 1 Share Posted July 1 This may be of interest to someone, somewhere. Presented with all my apologies to Knuth and Welford, 10 DIM S$(10):S$="9999999994" 20 N0=VAL(S$)+VAL(S$(10)) 30 N=N0:RM1=99:REM 10000*RND(0) 40 N1=N:N=N+1:IF (N-N1)<1 THEN 90 50 X=10000*RND(0):RM1=RM1+((X-RM1)/N) 60 PRINT INT(N/10);N-(10*INT(N/10)); 70 PRINT " ";N-N0;" ";X;" ";RM1 80 GOTO 40 90 PRINT "MEAN = ";RM1 99 END Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted July 3 Share Posted July 3 On 7/1/2024 at 9:39 PM, yetanothertroll said: I'm not sure why the base 100 thing is so bad. The problem is the size of the error in number representations if you have to work with a finite number of digits in a basis b. Thus, for example, it is not too hard to see that the largest relative error for a floating point representation with a finite (fixed) number of digits is b-1, so 1 for binary systems, but 99 for the BCD choice of the math pack. 1 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted July 3 Share Posted July 3 (edited) 1 hour ago, thorfdbg said: The problem is the size of the error in number representations if you have to work with a finite number of digits in a basis b. Thus, for example, it is not too hard to see that the largest relative error for a floating point representation with a finite (fixed) number of digits is b-1, so 1 for binary systems, but 99 for the BCD choice of the math pack. I'm just not seeing egregiously bad results. Sure, sometimes I resort to little tricks like X=X*X:X=X*X:X=X*X instead of X=X^8, but I haven't felt the need to go full Kahan–Babuška to sum an array as of yet. Could things be a little better with a replacement mathpack based on Turbo Pascal's six byte real or a 48-bit MBF? Maybe. Buuut, packed BCD made the conversions from/to human-readable ATASCII much easier and faster, but that sign bit had to go somewhere, and if they went with base 10 instead of 100, that seven bit exponent wouldn't go very far. That really could drive you into strange territories just to find the sum or product of an array, file, or READ/DATA stream Edited July 3 by yetanothertroll Dang typos Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted July 3 Share Posted July 3 The issue appears for addition and subtraction, requiring denormalization and normalization. 1 Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted July 3 Share Posted July 3 Just now, thorfdbg said: The issue appears for addition and subtraction, requiring denormalization and normalization. Yup, and that line buffer could have been used to denormalize into a base 10 format for intermediate results. Maybe one of those third party replacements mathpacks did exactly that Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted July 11 Share Posted July 11 On 7/3/2024 at 11:12 AM, thorfdbg said: The issue appears for addition and subtraction, requiring denormalization and normalization. I'm starting to wonder about that. It may not be necessary to denormalize the operands, only to normalize the result. It might not be the fastest way, but it could be done if you had a spare 200+ bytes lying around to hold the intermediate result. I'll try to offer a proof by construction, most likely in FastBasic, when I have a chance Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted July 12 Share Posted July 12 OK, this FastBasic code is kind of a hot mess, but if you really really want to be able to count to 1.23456789E97 by 1.23456789E-97s and actually expect to get to 1.23456789E97, eventually, someday, maybe in a few billion years or so, here's one way you can do it, ' Program FPAccumulator Print Fre(); " "; LM = DPeek(82) ' Preserve text window margins Poke 82, 0 ' Set left and right margin to max Poke 83, 39 Dim Z%(3) Acc$ = Str$(0) ' Just allocate those 256 bytes already MSet Adr(Acc$) + 1, 255, 0 Poke Adr(Acc$), 255 ' or use this as an an overflow sentinel? Print Fre() Do Input "Number or Q to quit? "; X$ If X$ = "Q" Then Exit Print X$; " entered" Z%(0) = Abs(Val(X$)) Print Z%(0); @FPDump Adr(Z%) + 0 ' Add "X" to Accumulator XExpn = 127 & Peek(Adr(Z%) + 0) Carry = 0 For i = 5 To 1 Step -1 XSuperD = Peek(Adr(Z%) + 0 + i) AccumSD = Peek(Adr(Acc$) + 127 - XExpn + i) D1 = (XSuperD & 15) + (AccumSD & 15) + Carry If D1 < 10 Carry = 0 Else Carry = 1 D1 = D1 - 10 EndIf D2 = (XSuperD / 16) + (AccumSD / 16) + Carry If D2 < 10 Carry = 0 Else Carry = 1 D2 = D2 - 10 EndIf Poke Adr(Acc$) + 127 - XExpn + i, ((D2 * 16) ! D1) Next i i = 0 While Not (Carry = 0) ' NB: No attempt is made to deal with overflow! AccumSD = Peek(Adr(Acc$) + 127 - XExpn + i) D1 = (AccumSD & 15) + Carry If D1 < 10 Carry = 0 Else Carry = 1 D1 = D1 - 10 EndIf D2 = (AccumSD / 16) + Carry If D2 < 10 Carry = 0 Else Carry = 1 D2 = D2 - 10 EndIf Poke Adr(Acc$) + 127 - XExpn + i, ((D2 * 16) ! D1) Dec i Wend ' Show accumulator Print "A= "; i = 1 Do If Not (i < 256) Then Exit If Not (Peek(Adr(Acc$) + i) = 0) Then Exit Inc i Loop j = 255 Do If Not (0 < j) Then Exit If Not (Peek(Adr(Acc$) + j) = 0) Then Exit Dec j Loop If Not (i <= j) Print "I guess it's zero" Else AccExp = 128 - i - 64 For k = i To j If (i + 1) = k Print "."; ElIf (i + 1) < k Print "'"; EndIf AccumSD = Peek(Adr(Acc$) + k) Print AccumSD / 16; AccumSD & 15; Next k Print "*100^"; AccExp ' Export accumulator to Atari FP Poke Adr(Z%) + 6, 128 - i ' 0 < i Poke Adr(Z%) + 7, Peek(Adr(Acc$) + i + 0) Poke Adr(Z%) + 8, Peek(Adr(Acc$) + i + 1) Poke Adr(Z%) + 9, Peek(Adr(Acc$) + i + 2) Poke Adr(Z%) + 10, Peek(Adr(Acc$) + i + 3) Poke Adr(Z%) + 11, Peek(Adr(Acc$) + i + 4) . If $50 <= Peek(Adr(Acc$) + i + 5) Then ' Should I try to round up or not? Print " = "; Z%(1) EndIf Loop While Key() : Get ZZ : Wend Print Print "OK" Get ZZ DPoke 82, LM End Proc FPDump Za Data Hex() Byte ROM = "0123456789ABCDEF" ' Hex dump Print ":", "$"; For i = 0 to 5 If i Then Print "'"; j = Peek(Za + i) Print Chr$(Hex(1 + (j / 16))); ' So which way of doing this is better? Print $(&Hex)[1 + (j & 15), 1]; ' I have absolutely no idea whatsoever! Next i Print ' Quick and dirty Str$(), sort of Print " = "; If (Peek(Za) & 128) Then Print "-"; For i = 1 to 5 j = Peek(Za + i) Print $(&Hex)[1 + (j / 16), 1]; Print Chr$(Hex(1 + (j & 15))); If i = 1 Then Print "."; Next i Print " * 100 ^ "; (127 & Peek(Za)) - 64 EndProc Quote Link to comment Share on other sites More sharing options...
sanny Posted July 12 Share Posted July 12 On 6/23/2024 at 3:44 PM, ClausB said: Also sales tax percentage, 4% or 0.04 Wow! Sales tax 4%. Is it still that way over at your location? 2 Quote Link to comment Share on other sites More sharing options...
-=Psycho=- Posted Thursday at 09:21 PM Share Posted Thursday at 09:21 PM I am not a mathematician by any stretch, but my understanding of the anomalies inherent to Atari's floating point spec is indeed due to its base-100 exponents. This much has been discussed here already, but what appears to have escaped mention is that, despite the name, the decimal point isn't floating at all - it's fixed to the right of the first mantissa byte. You can only virtually "float" this decimal by manipulating the exponent value, but because the exponent is base-100, the decimal can only be moved in multiples of 2 positions in either direction. "Ok -=P=-, so what if it's necessary to move the decimal just one position?" I'm glad you asked! The work-around is to shift the mantissa digits rightward to mate it appropriately to the fixed decimal point when necessary, thereby truncating the 10th digit and consequently yielding only 9 digits of precision. Perhaps they should have more appropriately labeled the specification, "floating precision"? -=P=- Unstretched mathematician. Quote Link to comment Share on other sites More sharing options...
+yetanothertroll Posted Thursday at 11:38 PM Share Posted Thursday at 11:38 PM 2 hours ago, -=Psycho=- said: I am not a mathematician by any stretch, but my understanding of the anomalies inherent to Atari's floating point spec is indeed due to its base-100 exponents. This much has been discussed here already, but what appears to have escaped mention is that, despite the name, the decimal point isn't floating at all - it's fixed to the right of the first mantissa byte. You can only virtually "float" this decimal by manipulating the exponent value, but because the exponent is base-100, the decimal can only be moved in multiples of 2 positions in either direction. "Ok -=P=-, so what if it's necessary to move the decimal just one position?" I'm glad you asked! The work-around is to shift the mantissa digits rightward to mate it appropriately to the fixed decimal point when necessary, thereby truncating the 10th digit and consequently yielding only 9 digits of precision. Perhaps they should have more appropriately labeled the specification, "floating precision"? -=P=- Unstretched mathematician. Yup, multiplying or dividing by 10 can zap any tenth decimal digit. It's easy to see if you're using a version of Basic that makes it easy to hex-dump floats. It might be best to simply ignore the tenth decimal digit if there is one, like Atari BASIC appears to do, sometimes, when it feels like it Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.