Discussion:
bug?
(too old to reply)
Fried
2003-10-05 00:33:32 UTC
Permalink
'possible bug in pbcc3.02
'
'the following code gives an example of the bug.
'note m$ should equal n$ but they do not

#DIM ALL
FUNCTION PBMAIN()
DIM m AS STRING
DIM n AS STRING
DIM v AS LONG

m$="3999.9"
v=VAL(m$)+.1
m$=STR$(v)
m$=RIGHT$(m$,LEN(m$)-1)

n$="3999.9"
n$=STR$((VAL(n$)+.1))
n$=RIGHT$(n$,LEN(n$)-1)

PRINT m$
PRINT n$

WAITKEY$
END FUNCTION
Tom Lake
2003-10-05 01:16:16 UTC
Permalink
Post by Fried
'possible bug in pbcc3.02
'
'the following code gives an example of the bug.
'note m$ should equal n$ but they do not
It's not a bug at all. The problem is in every BASIC interpreter/compiler
and involves single to double precision conversion. When you add a single
precision .1 to a double precision value, you get leftovers. This is
because you can't make something from nothing. You're only giving it 7
digits but expecting 16 digits of precision. It ain't gonna happen. Below
is a fix, using a double precision .1# so you are adding all 16 digits of
precision.

Here's a shorter example: n# = .1: PRINT n#

n$="3999.9"
n$=STR$((VAL(n$)+.1#)) ' See the difference in this line?

PRINT m$
PRINT n$

Now m and n$ are the same.

Tom Lake
sinewave
2003-10-05 12:12:07 UTC
Permalink
i wanted to add that these math problems are not unique to BASIC. the fpu
(hardware) cannot represent some numbers exactly in binary notation. see
IEEE 754.

regards,
phil
Judson McClendon
2003-10-23 16:05:47 UTC
Permalink
Post by sinewave
i wanted to add that these math problems are not unique to BASIC. the fpu
(hardware) cannot represent some numbers exactly in binary notation. see
IEEE 754.
Actually, it's not BASIC or the FPU per se, but the fact that, while every
integer can be expressed exactly in any integer base, some real numbers can
be expressed exactly in some bases, but not in others. For example 1/10 and
1/100 can be expressed exactly in base 10, but not in base 2. Each results in
an infinitely repeating series, as 1/3 or 1/7 do in base 10. Most compilers
generate code to round results when converting back to decimal for printing,
so you don't normally see this. However, when a single precision infinitely
repeating series is assigned to a double variable, the code has no way of
knowing this at the time, so cannot extend the repeating series to fill the
longer variable. When the time comes to print, the double precision value is
rounded at the end, not at the point where the single precision variable ended.
There is *only one* solution to this particular problem, and that is to use
scaled decimal variables. This is also why languages that do not support
scaled decimal variables (PB does) are *unacceptable* for handling money,
no matter what their proponents may think or say.
--
Judson McClendon ***@sunvaley0.com (remove zero)
Sun Valley Systems http://sunvaley.com
"For God so loved the world that He gave His only begotten Son, that
whoever believes in Him should not perish but have everlasting life."
sinewave
2003-10-23 16:14:07 UTC
Permalink
hi Judson:

thank you for the nice explaination.

regards,
phil
JQP
2003-10-23 17:31:39 UTC
Permalink
Post by Judson McClendon
This is also why languages that do not support
scaled decimal variables (PB does) are *unacceptable* for handling money,
no matter what their proponents may think or say.
Regardless of what BASIC proponents may think or say, scaled decimal
variables are not required for accurate monetary calculations.

There is no *magic* surrounding scaled decimals (I assume you're referring
to the currency type in PB). Internally, these are just plain integers with
an implied scaling factor of 10000. Simple multiplication and division,
nothing more.

A few simple macros can implement similar functionality and provide
identical results using nothing but plain integers. Having these macros
built into the language may be convenient; especially for those who lack the
ability to write them, but it is not a requirement.
Judson McClendon
2003-10-24 14:49:11 UTC
Permalink
Post by JQP
Post by Judson McClendon
This is also why languages that do not support
scaled decimal variables (PB does) are *unacceptable* for handling money,
no matter what their proponents may think or say.
Regardless of what BASIC proponents may think or say, scaled decimal
variables are not required for accurate monetary calculations.
There is no *magic* surrounding scaled decimals (I assume you're referring
to the currency type in PB). Internally, these are just plain integers with
an implied scaling factor of 10000. Simple multiplication and division,
nothing more.
A few simple macros can implement similar functionality and provide
identical results using nothing but plain integers. Having these macros
built into the language may be convenient; especially for those who lack the
ability to write them, but it is not a requirement.
No, it's not 'required', in the sense that you can do it the hard way, just as
you 'can' move a mountain with a teaspoon. But to follow your suggestion
would make almost every operation on every such field nearly an order of
magnitude more complex. Every arithmetic operation must be scaled, every
input or print must be scaled, and in every reference to a scaled field, the
programmer must be conscious of the scaling (that it's there, and how much
for each field). Complexity means more effort, more errors, and less
efficiency. A compiler can be expected to handle such operations with no
errors, but programmers are not so reliable. Just imagine how neat it would
be in calculating the payment amount on a loan, or in doing least regression
analysis. What is the point in creating such a situation, when there are
languages created for the purpose? Do you recommend doing your own
floating point calculations as well? ;-)

I'm not a 'BASIC advocate', I'm an advocate of using tools well suited for
the task at hand. While I love BASIC for certain tasks, most of my code is
in other languages.
--
Judson McClendon ***@sunvaley0.com (remove zero)
Sun Valley Systems http://sunvaley.com
"For God so loved the world that He gave His only begotten Son, that
whoever believes in Him should not perish but have everlasting life."
JQP
2003-10-25 03:46:20 UTC
Permalink
Post by Judson McClendon
But to follow your suggestion
would make almost every operation on every such field nearly an order of
magnitude more complex.
Here's the math.

Currency type -------------

Add: Z=X+Y
Subtract: Z=X-Y
Multiply: Z=X*Y
Divide: Z=X\Y

Scaled Integers----------

Add: Z=X+Y
Subtract: Z=X-Y
Multiply: Macro CurMul(X,Y) = (X*Y)\10000
Divide: Macro CurDiv(X,Y) = (X\Y)*10000
String: Macro CurStr(Z) = FORMAT$(Z\10000)+"."+FORMAT$(ABS(Z) MOD
10000,"0000")

Addition and subtraction are unaffected
X*Y gets replaced by CurMul(X,Y)
X\Y gets replaced by CurDiv(X,Y)
Str$(Z) gets replaced by CurStr(Z)

Does this look an order of magnitude more complex to you?
Judson McClendon
2003-10-25 12:37:06 UTC
Permalink
Post by JQP
But to follow your suggestion would make almost every operation
on every such field nearly an order of magnitude more complex.
Here's the math.
Currency type -------------
Add: Z=X+Y
Subtract: Z=X-Y
Multiply: Z=X*Y
Divide: Z=X\Y
Scaled Integers----------
Add: Z=X+Y
Subtract: Z=X-Y
Multiply: Macro CurMul(X,Y) = (X*Y)\10000
Divide: Macro CurDiv(X,Y) = (X\Y)*10000
String: Macro CurStr(Z) = FORMAT$(Z\10000)+"."+FORMAT$(ABS(Z) MOD
10000,"0000")
Addition and subtraction are unaffected
X*Y gets replaced by CurMul(X,Y)
X\Y gets replaced by CurDiv(X,Y)
Str$(Z) gets replaced by CurStr(Z)
The errors in your examples above clearly illustrate my point. Consider
your statement: "Addition and subtraction are unaffected". Try adding
two numbers with different scaling (e.g. two and four places to the right
of the decimal). Zing! A similar problem applies with all your other
operations. What? You didn't think that you sometimes need two decimal
places (e.g. currency) and sometimes 3 or 4 (e.g. interest rates), and
sometimes 6 or more (e.g. unit cost), even after I pointed that out: "the
programmer must be conscious of the scaling (that it's there, and how
much for each field)"? :-)

You made an assumption that I was advocating BASIC, even after I stated
otherwise. Exactly my point: all people, including programmers, are error
prone, you and me as well. While a fixed scaled variable type is better
than none at all, only variably scaled decimal fields (e.g. COBOL, PL/I)
are best suited for serious financial work. Anything else requires more
complex programming, which means human programmers *will* make
more errors. Humans can do complex things, but they *do* make more
errors when doing more complex things. Unquestionably, undeniably,
easily provable and widely known and understood by anyone even slightly
familiar with human psychology. Q.E.D. ;-)
Post by JQP
Does this look an order of magnitude more complex to you?
Well, your 'this' isn't sufficient. And the complexity is more than simply
X bytes more code. The programmer's constant need to be aware of the
requirement, the documentation and training considerations, and the
human propensity to do the intuitive but incorrect, are probably much
more significant. When you consider what it really does take, it is at
least an order of magnitude more complex. The complexity of doing what
is simple, intuitive and obvious is virtually nil.

The idea should be to work with human nature, not against it. Use human
characteristics to advantage, don't ignore them. Over many years of
working in situations requiring very high precision, I have seen this to
always be much, much better. Unfortunately, this is an area in which most
programmers are virtually clueless. You can see this clearly in the design
of reports and many computer languages. The designers usually try to look
at things from an abstract logical standpoint. But humans are not abstract
logical creatures. We do such things with difficulty, and it takes much
practice and discipline to do them well. We will never be as precise as
machines in such things. But we do have strengths, such as habit and
intuition, and learned patterns of thought. These are more difficult to
quantify, but it is not so difficult to recognize patterns of behavior, both
physical and psychological. For example, humans have an expanded
ability to learn verbal language when young. These learned language
patterns are 'subliminated' (a form of mental abstraction) at an early age,
and become deeply ingrained. And since programming languages are
always learned at a much later age than verbal languages, they will never,
ever, ever be as deeply ingrained in a human mind as a native verbal
language. It is a simply unavoidable consequence that programming
languages which exploit these patterns will be easier to learn and master
than those that go against them. Logical elegance will never outweigh or
outperform facility, in the human psyche. Better to recognize this and use
it to our advantage.
--
Judson McClendon ***@sunvaley0.com (remove zero)
Sun Valley Systems http://sunvaley.com
"For God so loved the world that He gave His only begotten Son, that
whoever believes in Him should not perish but have everlasting life."
Judson McClendon
2003-10-25 18:47:20 UTC
Permalink
Try adding two numbers with different scaling (e.g. two and four places to
the > right of the decimal). Zing! A similar problem applies with all your
other operations.
The built-in currency type avoids this little problem in a straightforward
way; it never uses "different scaling". It always carrying 4 decimal
places internally. In other words, it always scales any input value by
10000. You get 4 decimals whether you want them or not. My example
followed the same approach.
For your amusement and education, I've attached a PB program which provides
a macro based simulation of the currency type using only long integers.
Includes input and string conversion and rounding of the final result to 2
decimals. Short example calc also provided. Note that the results are
*identical* to the currency based code.
Admittedly, the macros are not quite as clean but it is not an order or
magnitude more complex.
Hummm. What we have here is a failure to communicate. :-)

Did you actually read my post? You can't always use 4 decimal places.
That is too many to properly round money in all cases (some algorithms
require rounding of intermediate results to specific precision), and too
few to carry all values, such as unit cost on some mass produced items.

Thanks for the code, but I have a bit of experience with decimal math,
rounding and so fourth. The program BIGCALC (can download with
source from my website below) is an example. BIGCALC is a RPN
calculator written in C, not BASIC, that can do very high precision
(> 1,000 digits) decimal math, including most common transcendental
functions. I wrote BIGCALC just for fun in 1987-88. If you ever need to
calculate cos(pi^3.5/e)^sqr(6.023*10^23) to 500 digits, BIGCALC is
just the ticket. Some interesting folks like NASA, HP, Ames Research
Center, Cape Canaveral and LLL bought BIGCALC when it was
shareware, the math library has been used in three commercial products,
and parts of the source have appeared in publications from Microsoft
and others. Note that BIGCALC is a DOS application, but it runs fine
under any flavor of Windows. I would like to add a GUI interface and
programming capability 'one of these days'.

See? I'm not a BASIC Bigot. :-)
--
Judson McClendon ***@sunvaley0.com (remove zero)
Sun Valley Systems http://sunvaley.com
"For God so loved the world that He gave His only begotten Son, that
whoever believes in Him should not perish but have everlasting life."
JQP
2003-10-26 05:14:18 UTC
Permalink
Post by Judson McClendon
Did you actually read my post? You can't always use 4 decimal places.
I read it but it didn't make much sense. PB's currency type carries 4
decimal places just like my macros. They are functional equivalents. My
example shows that the results are *identical*.
Post by Judson McClendon
That is too many to properly round money in all cases (some algorithms
require rounding of intermediate results to specific precision), and too
few to carry all values, such as unit cost on some mass produced items.
So is support for a currency type required or not when handling money? This
discussion began when you declared that they are.

"Judson McClendon" <***@sunvaley0.com> wrote in message news:20031023120639.984$***@news.newsreader.com...
"This is also why languages that do not support scaled decimal variables (PB
does) are *unacceptable* for handling money,..."

I've shown that it is fairly easy to duplicate the functionality of
PB's currency type in most any language using a few simple macros. The task
of handling money is not "an order of magnitude" more complex without these
macros built into the language itself.
Michael Mattias
2003-10-26 12:43:00 UTC
Permalink
Post by JQP
Post by Judson McClendon
Did you actually read my post? You can't always use 4 decimal places.
I read it but it didn't make much sense. PB's currency type carries 4
decimal places just like my macros. They are functional equivalents. My
example shows that the results are *identical*.
Post by Judson McClendon
That is too many to properly round money in all cases (some algorithms
require rounding of intermediate results to specific precision), and too
few to carry all values, such as unit cost on some mass produced items.
So carry the cost on those mass-produced items per hundred, or per thousand.
That worked for me for the twenty years I was in the distribution and
manufacturing industries.

Rounding? If you don't like a compiler's 'default' rounding, write your own
rounding functions. And rounding of intermediate values? As long as you are
writring your own rounding functions, change the order of the operands in
those routines and/or round the intermediate results yourself.

MCM

Loading...