15

I am mildly curious that though the 6502 provides BCD arithmetic which would be useful for implementing decimal floating point, Commodore BASIC uses, like all (?) Micro-Soft BASIC, binary floating point instead.

Are there any easy example that show precision errors in Commodore BASIC, that would not be present if it would be based on decimal FP?

A classic test of the difference is 0.1 + 0.2 = 0.3; this evaluates to false in pretty much every modern language (since almost all of them use the IEEE floating point that is built into modern hardware). There is even a website devoted to this oddity: 0.30000000000000004.com

I tried this on a C64 emulator (which uses the same BASIC as the PET) and to my astonishment, it correctly evaluated to true. So did some other obvious tests like 0.1 * 10 = 1 and 0.1 + 0.9 = 1 but they worked as well.

What test would give a wrong answer on Commodore BASIC? That is, I'm not asking for a way to get it to demonstrate rounding errors per se; that much is trivial. I'm asking for a way to get it to give a wrong answer, not because it lacks infinite precision, but specifically for(simple) cases where decimal arithmetic would give the right answer. Some Commodore BASIC (MS-BASIC) equivalent to the 0.1 + 0.2 = 0.3 test on IEEE 754.

  • 5
    It might be worth to remember that the PET at first was A machine, not a business or home. If at all it was meant as a hobby computer. The differentiation in business or home is something that only evolved later - and with it's missing colour and sound abilities it moved into a (more) business range. – Raffzahn Jan 27 at 12:52
  • 1
    @Raffzahn True! I tried it on an Apple II emulator just now and it passes the test, though iirc the Apple II ended up using Microsoft BASIC just like Commodore so that's not surprising. I'll try it on some others if I can find emulators with working keyboards. – rwallace Jan 27 at 13:00
  • 1
    This question is out of the ordinary, and I must admit I really like it. Not at least as it looks for easy repeatable tests over some lengthy explanation. A true Engineering aproach :)) Would you mind to rephrase it (mostly the first paragraph) a bit to focus on the core issue of PET/Commodore FP - as the title already expresses it quite good (maybe also adding "... precision" in the title) I can do as well if you like me to. That way it'll make a great stop for others searching for hints in the same direction. – Raffzahn Jan 27 at 14:47
  • 1
    @Raffzahn Thanks! The rephrase is an interesting idea, sure, please go ahead. – rwallace Jan 27 at 15:25
  • 2
    @tofro But that wasn't the question. It's not about if the representation with 10 decimal digits is the same but if the actual numbers are the same. So don't print and visually compare the output but actually compare the numbers and print the outcome of that comparison. – BlackJack Jan 27 at 17:56
14

This example reveals a rounding error under Commodore BASIC V2.0:

  A=0.3:B=0.6:IF A+B<>0.9 THEN PRINT A+B-0.9

Running this on a C64 yields a difference of 2.32830644e-10. Other pairs that fail are 0.4+0.5, 0.6+0.1 and 0.8+0.1. Please note that also the order in which the numbers are summed up affects the result. 0.6+0.1-0.7 yields a difference, while 0.1+0.6-0.7 results to 0.

9

Here is my favourite example for this problem. I often use it to show Excel's mathematical shortcomings, but not surprisingly it works the same in the C64:

10 A = 0.1
20 B = 0.1
30 FOR I = 1 TO 10
40 D = B
50 B = 20 * A - 19 * B
60 PRINT B
70 A = D
80 NEXT I

In every iteration, the algorithm should be doing 20 * 0.1 - 19 * 0.1 = 0.1, but the output on this simulator is

 .0999999999
 .100000002
 .0999999578
 .100000845
 .0999831052
 .100337895
 .0932421037
 .235157925
-2.60315849
 54.1631699
5

Might I suggest you try 0.11+0.12?

I believe IEEE754 will in fact give the right answer on 0.1+0.2=0.3, using standard single precision. It is, however, not difficult to provoke IEEE754 failures, for instance on 0.11+0.12. The C program below show the raw bin32 representations of the relevant IEEE754 numbers, the program output is:

a  :3dcccccd
b  :3e4ccccd
a+b:3e99999a
c  :3e99999a
IEEE754 copes
a  :3de147ae
b  :3df5c28f
a+b:3e6b851e
c  :3e6b851f
IEEE754 fails

Program:

#include <stdio.h>
#include <stdint.h>
int main( void ) {
    float a = 0.1;
    float b = 0.2;
    float c = 0.3;
    float apb = a+b;
    printf( "a  :%x\n", *(uint32_t *)&a);
    printf( "b  :%x\n", *(uint32_t *)&b);
    printf( "a+b:%x\n", *(uint32_t *)&apb);
    printf( "c  :%x\n", *(uint32_t *)&c);
    if ( a + b == c ) {
            printf( "IEEE754 copes\n" );
    } else {
            printf( "IEEE754 fails\n" );
    }

    a = 0.11;
    b = 0.12;
    c = 0.23;
    apb = a+b;
    printf( "a  :%x\n", *(uint32_t *)&a);
    printf( "b  :%x\n", *(uint32_t *)&b);
    printf( "a+b:%x\n", *(uint32_t *)&apb);
    printf( "c  :%x\n", *(uint32_t *)&c);
    if ( a + b == c ) {
            printf( "IEEE754 copes\n" );
    } else {
            printf( "IEEE754 fails\n" );
    }

    return 0;
}
  • 1
    Ah! I ran the .1+.2 test on a modern machine in double precision; maybe in some sense, single precision is not precise enough to show the difference; CBM BASIC is closer to single precision. But .11+.12=.23 does indeed fail on a C64. – rwallace Jan 27 at 14:04
  • 2
    On every half decent implementation, 0.1 + 0.2 will give you something that is very, very close to 0.3. Whether it equals 0.3 is more or less coincidence. The actual precision doesn't matter, double precision will be much much closer to 0.3, but will also make a lot lot smaller difference "not equal". – gnasher729 Jan 27 at 19:21
  • @gnasher729 Sure... what it equals or not, in the test, is the number produced by the string "0.3", which is 5*2^54 less than 0.3 in double precision, vs 0.1 + 0.2 being 5*2^52 greater. – Random832 Jan 29 at 4:25

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.