LBB bug?

Discussions related to mathematics, numerical methods, graph plotting etc.
Richard Russell
Posts: 477
Joined: Tue 18 Jun 2024, 09:32

LBB bug?

Post by Richard Russell »

This message recently appeared at the BB4W Discussion Group, despite being about LBB:
If, for example, tempEval is 4.2 then A evaluates correctly to 420 but B arrives at 419, throwing up an error.

A=(tempEval * 100) : B=int(tempEval * 100)
if (tempEval * 100) <> int(tempEval * 100) then print #Foz.info, "Too many decimal places for empty value!": valerr = 1: return

It doesn't seem to be a problem in Liberty Basic so I'm wondering if there is a small tweak that can be done to correct this in LBB
This is a Frequently Asked Question which has been answered many times before; every newcomer to programming languages (it's not at all specific to BASIC) seems to hit this particular misunderstanding sooner or later. So, once again, let's work through it step by step:

Code: Select all

  tempEval = 4.2
This attempts to set the variable tempEval to 4.2, but like the vast majority of programming languages BBC BASIC (hence also LBB) works internally in binary floating point and that value cannot be represented precisely in that format. In fact, the exact value stored in tempEval is
4.199999999999999999826527652402319290558807551860809326171875
which is very close to 4.20, but not precisely equal.

Code: Select all

  A=(tempEval * 100)
This sets the variable A equal to tempEval * 100, and since tempEval was not exactly 4.20, A will not be exactly 420. The exact value stored in A is in fact 419.9999999999999999722444243843710864894092082977294921875.

Code: Select all

  B=INT(tempEval * 100)
This sets B to the integer part of tempEval * 100, that is it truncates the value to the next lowest integer, which is of course 419. Hence there's nothing wrong or surprising here, everything is working as expected.

As for the comment that "It doesn't seem to be a problem in Liberty Basic" this is not the case: the issue does affect Liberty BASIC (it, too, uses binary floating point) but because it works internally to a lower precision than LBB different values are affected.

Specifically, the closest value to 4.20 that Liberty BASIC can represent is 4.20000000000000017763568394002504646778106689453125 which is less accurate than the LBB approximation, but because it is slightly more than 4.2 rather than slightly less the truncation works 'as expected'.

But, crucially, try 4.10 instead, which Liberty BASIC can represent most closely as 4.0999999999999996447286321199499070644378662109375 and now the truncation to an integer of 4.10 * 100 will give 409 rather than the 'expected' 410, which is exactly the same issue - just affecting different numbers.

In summary, most programming languages work internally in binary floating point which cannot precisely represent many (non-integer) decimal numbers, and you need to be aware of the consequences of that.