1. BUG! Erratic for loop behavior
Hello,
The output of this loop:
------------------------------
for i = 9.4 to 10.0 by .1 do
? i
end for
------------------------------
stops at 10, as expected.
The output of this loop:
------------------------------
for i = 31.1 to 34.2 by .1 do
? i
end for
------------------------------
stops at 34.1 (!), NOT as expected.
The output of this loop:
------------------------------
for i = 131.1 to 134.2 by .1 do
? i
end for
------------------------------
stops at 134.2, as expected.
The output of this loop:
------------------------------
for i = 60.0 to 64.5 by .1 do
? i
end for
------------------------------
stops at 64.4, NOT as expected.
I've verified this on exw.exe & ex.exe, as well as translated to C. It
looks like an outright bug to me.
2. Re: BUG! Erratic for loop behavior
Andy Serpa wrote:
> ...
> ------------------------------
> for i = 31.1 to 34.2 by .1 do
> ? i
> end for
> ------------------------------
> stops at 34.1 (!), NOT as expected.
>
Hi Andy,
that's ok. Look at this:
for i = 31.1 to 34.1 by 0.1 do
printf(1,"%20.15f\n",i)
end for
and you will notice why: the decimal given value 0.1 is exactly
representable in the computer for it has to stores it internally as an
binary value with a limited number of bits. Actually, 0.1 (dec.) is has
an unlimited binary representation: 0.0001100110011..... . This is the
correct way to do it (have in mind that 31.1 and 34.1 are also not
exactly representable!):
for i = 311 to 341 by 1 do
printf(1,"%20.15f\n",i/10)
end for
Have a nice day, Rolf
3. Re: BUG! Erratic for loop behavior
"Rolf Schröder" wrote:
> ..
> ... the decimal given value 0.1 is exactly
> representable ...
It should be: ... the decimal given value 0.1 is NOT exactly
reresentable ... .
Sorry, Rolf
4. Re: BUG! Erratic for loop behavior
- Posted by rforno at tutopia.com
Mar 23, 2002
Of course you are right. The desirable behavior is that lost precision does
not interfere with exact results. But the solution to this problem is costly
in processing time. Should Euphoria fix it, it would be much slower.
There are a couple of programming languages where this problem does not
practically exist. These are APL (in which a fuzz is considered in
comparisons) and ABC (a language from the Netherlands, which does arithmetic
with [nearly] infinite digits, and that does not lose precision even after
assigning a number such as 0.3 to a variable). But they are much slower than
Euphoria.
Regards.
----- Original Message -----
From: "Andy Serpa" <renegade at earthling.net>
To: "EUforum" <EUforum at topica.com>
Subject: RE: BUG! Erratic for loop behavior
>
> Here's another example:
>
> atom sum
> sum = 60.0
>
> for i = 1 to 45 do
> sum += .1
> end for
> ? sum
> ? equal(sum,64.5)
> ? (sum = 64.5)
> Output is:
>
> 64.5
> 0
> 0
>
> Please don't tell me this is desirable behavior. Explaining the cause
> of the problem doesn't remove the problem. I am well aware of how
> computers represent numbers but since I'm only dealing with one decimal
> place I should get at least that much precision (actually, reverse that
> -- I am getting too much precision) when doing comparsions...
>
>
> Andy Serpa wrote:
> >
> > Rolf Schröder wrote:
> > > Andy Serpa wrote:
> > > > ...
> > > > ------------------------------
> > > > for i = 31.1 to 34.2 by .1 do
> > > > ? i
> > > > end for
> > > > ------------------------------
> > > > stops at 34.1 (!), NOT as expected.
> > > >
> > > Hi Andy,
> > >
> > > that's ok. Look at this:
> > >
> > > for i = 31.1 to 34.1 by 0.1 do
> > > printf(1,"%20.15f\n",i)
> > > end for
> > >
> > > and you will notice why: the decimal given value 0.1 is exactly
> > > representable in the computer for it has to stores it internally as an
> > > binary value with a limited number of bits. Actually, 0.1 (dec.) is
has
> > > an unlimited binary representation: 0.0001100110011..... . This is the
> > > correct way to do it (have in mind that 31.1 and 34.1 are also not
> > > exactly representable!):
> > >
> > > for i = 311 to 341 by 1 do
> > > printf(1,"%20.15f\n",i/10)
> > > end for
> > >
> >
> > Yeah, that's not really good enough for me -- .1 should be .1 in a loop.
> > The Euphoria manual even has an example under the FOR loop section
> > using a .3 "by" value... Is this also a "feature"?
> >
> >
>
>
>
5. Re: BUG! Erratic for loop behavior
On Sat, 23 Mar 2002 20:36:14 +0100, Rolf Schröder <r.schr at t-online.de>
wrote:
>Actually, 0.1 (dec.) is has
>an unlimited binary representation: 0.0001100110011..... .
Sanity check required. Kinda understand. Kinda appreciate I may have
been mollycoddled over many years, or somesuch.
Where'd you get this from, please.
Pete
6. Re: BUG! Erratic for loop behavior
On Sat, 23 Mar 2002 22:18:30 +0000, Chris Bensler <bensler at mail.com>
wrote:
>
>Do a search for "floating point precision" in the mailing list archives.
Heh heh hey, 5,247 messages!
Pete
d8=
7. Re: BUG! Erratic for loop behavior
Andy,
Although I assume this is at least obvious, you could just do this:
for i = 10*31.1 to 10*34.2 do
?i/10
end for
Same for whatever max "level" of floating point you have, ie, if *any* value
goes out to .001,multiply all by 1000, then divide, etc.
Maybe there's some good reason that doesn't occur to me offhand why this
won't work?
Dan Moyer
----- Original Message -----
From: "Andy Serpa" <renegade at earthling.net>
To: "EUforum" <EUforum at topica.com>
Sent: Saturday, March 23, 2002 11:19 AM
Subject: BUG! Erratic for loop behavior
>
> Hello,
>
>
> The output of this loop:
> ------------------------------
> for i = 9.4 to 10.0 by .1 do
> ? i
> end for
> ------------------------------
> stops at 10, as expected.
>
>
> The output of this loop:
> ------------------------------
> for i = 31.1 to 34.2 by .1 do
> ? i
> end for
> ------------------------------
> stops at 34.1 (!), NOT as expected.
>
>
> The output of this loop:
> ------------------------------
> for i = 131.1 to 134.2 by .1 do
> ? i
> end for
> ------------------------------
> stops at 134.2, as expected.
>
>
> The output of this loop:
> ------------------------------
> for i = 60.0 to 64.5 by .1 do
> ? i
> end for
> ------------------------------
> stops at 64.4, NOT as expected.
>
>
> I've verified this on exw.exe & ex.exe, as well as translated to C. It
> looks like an outright bug to me.
>
8. Re: BUG! Erratic for loop behavior
off the top of my head:
change the vars to sequence, check for '.', count how many to right of '.',
multiply by 10 to the how many for the MAX number in any var?
Dan
----- Original Message -----
From: "Chris Bensler" <bensler at mail.com>
To: "EUforum" <EUforum at topica.com>
Subject: RE: BUG! Erratic for loop behavior
>
> for i = var1 to var 2 by var3 do
> end for
>
> how much should the vars be multiplied by?
>
> Chris
>
> Dan Moyer wrote:
> > Andy,
> >
> > Although I assume this is at least obvious, you could just do this:
> >
> > for i = 10*31.1 to 10*34.2 do
> > ?i/10
> > end for
> >
> > Same for whatever max "level" of floating point you have, ie, if *any*
> > value
> > goes out to .001,multiply all by 1000, then divide, etc.
> >
> > Maybe there's some good reason that doesn't occur to me offhand why this
> > won't work?
> >
> > Dan Moyer
> >
> > ----- Original Message -----
> > From: "Andy Serpa" <renegade at earthling.net>
> > To: "EUforum" <EUforum at topica.com>
> > Sent: Saturday, March 23, 2002 11:19 AM
> > Subject: BUG! Erratic for loop behavior
> >
> >
> > > Hello,
> > >
> > >
> > > The output of this loop:
> > > ------------------------------
> > > for i = 9.4 to 10.0 by .1 do
> > > ? i
> > > end for
> > > ------------------------------
> > > stops at 10, as expected.
> > >
> > >
> > > The output of this loop:
> > > ------------------------------
> > > for i = 31.1 to 34.2 by .1 do
> > > ? i
> > > end for
> > > ------------------------------
> > > stops at 34.1 (!), NOT as expected.
> > >
> > >
> > > The output of this loop:
> > > ------------------------------
> > > for i = 131.1 to 134.2 by .1 do
> > > ? i
> > > end for
> > > ------------------------------
> > > stops at 134.2, as expected.
> > >
> > >
> > > The output of this loop:
> > > ------------------------------
> > > for i = 60.0 to 64.5 by .1 do
> > > ? i
> > > end for
> > > ------------------------------
> > > stops at 64.4, NOT as expected.
> > >
> > >
> > > I've verified this on exw.exe & ex.exe, as well as translated to C.
It
> > > looks like an outright bug to me.
> > >
> >
>
>
>
9. Re: BUG! Erratic for loop behavior
Chris,
Oops, I meant "change the var which was a number into a STRING...", then
look for the decimal point in that string, then see which var has the most
places to the right of the decimal point, and use that X10 as the
multiplier.
example code:
-- begin code:
include misc.e
integer multiplier, PosOfDecPoint
multiplier = 1
PosOfDecPoint= 0
atom var1, var2, var3
var1 = 31.1
var2 = 34.25
var3 = .01
sequence tempVar1, tempVar2, tempVar3
tempVar1 = sprint(var1)
tempVar2= sprint(var2)
tempVar3 = sprint(var3)
PosOfDecPoint = find('.', tempVar1)
if PosOfDecPoint then
if length(tempVar1) - PosOfDecPoint > multiplier then
multiplier = length(tempVar1) - PosOfDecPoint
end if
end if
PosOfDecPoint = find('.', tempVar2)
if PosOfDecPoint then
if length(tempVar1) - PosOfDecPoint > multiplier then
multiplier = length(tempVar2) - PosOfDecPoint
end if
end if
PosOfDecPoint = find('.', tempVar3)
if PosOfDecPoint then
if length(tempVar1) - PosOfDecPoint > multiplier then
multiplier = length(tempVar3) - PosOfDecPoint
end if
end if
for i = multiplier*var1 to multiplier*var2 by multiplier*var3 do
puts(1, sprint(i/multiplier) & " ")
end for
-- end code
Dan
----- Original Message -----
From: "Dan Moyer" <DANIELMOYER at prodigy.net>
To: "EUforum" <EUforum at topica.com>
Sent: Saturday, March 23, 2002 9:26 PM
Subject: Re: BUG! Erratic for loop behavior
>
> off the top of my head:
> change the vars to sequence, check for '.', count how many to right of
'.',
> multiply by 10 to the how many for the MAX number in any var?
>
> Dan
>
> ----- Original Message -----
> From: "Chris Bensler" <bensler at mail.com>
> To: "EUforum" <EUforum at topica.com>
> Sent: Saturday, March 23, 2002 9:02 PM
> Subject: RE: BUG! Erratic for loop behavior
>
>
> > for i = var1 to var 2 by var3 do
> > end for
> >
> > how much should the vars be multiplied by?
> >
> > Chris
> >
> > Dan Moyer wrote:
> > > Andy,
> > >
> > > Although I assume this is at least obvious, you could just do this:
> > >
> > > for i = 10*31.1 to 10*34.2 do
> > > ?i/10
> > > end for
> > >
> > > Same for whatever max "level" of floating point you have, ie, if *any*
> > > value
> > > goes out to .001,multiply all by 1000, then divide, etc.
> > >
> > > Maybe there's some good reason that doesn't occur to me offhand why
this
> > > won't work?
> > >
> > > Dan Moyer
> > >
> > > ----- Original Message -----
> > > From: "Andy Serpa" <renegade at earthling.net>
> > > To: "EUforum" <EUforum at topica.com>
> > > Sent: Saturday, March 23, 2002 11:19 AM
> > > Subject: BUG! Erratic for loop behavior
> > >
> > >
> > > > Hello,
> > > >
> > > >
> > > > The output of this loop:
> > > > ------------------------------
> > > > for i = 9.4 to 10.0 by .1 do
> > > > ? i
> > > > end for
> > > > ------------------------------
> > > > stops at 10, as expected.
> > > >
> > > >
> > > > The output of this loop:
> > > > ------------------------------
> > > > for i = 31.1 to 34.2 by .1 do
> > > > ? i
> > > > end for
> > > > ------------------------------
> > > > stops at 34.1 (!), NOT as expected.
> > > >
> > > >
> > > > The output of this loop:
> > > > ------------------------------
> > > > for i = 131.1 to 134.2 by .1 do
> > > > ? i
> > > > end for
> > > > ------------------------------
> > > > stops at 134.2, as expected.
> > > >
> > > >
> > > > The output of this loop:
> > > > ------------------------------
> > > > for i = 60.0 to 64.5 by .1 do
> > > > ? i
> > > > end for
> > > > ------------------------------
> > > > stops at 64.4, NOT as expected.
> > > >
> > > >
> > > > I've verified this on exw.exe & ex.exe, as well as translated to C.
> It
> > > > looks like an outright bug to me.
> > > >
> > >
10. Re: BUG! Erratic for loop behavior
Chris,
Oh. Didn't think about how *many* places could be multiplied into integers!
Well, I guess the idea is useful up to a point.
My code also had an error in it, besides being uninspired and not fully
thought out:
The line:
if length(tempVar1) - PosOfDecPoint > multiplier then
should only read like that for the FIRST test, not all three; in each other
test, it should be, respectively,
if length(tempVar2) - PosOfDecPoint > multiplier then
if length(tempVar3) - PosOfDecPoint > multiplier then
sorry.
corrected code:
include misc.e
integer multiplier, PosOfDecPoint
multiplier = 1
PosOfDecPoint= 0
atom var1, var2, var3
var1 = 31.1
var2 = 34.25
var3 = .01
sequence tempVar1, tempVar2, tempVar3
tempVar1 = sprint(var1)
tempVar2= sprint(var2)
tempVar3 = sprint(var3)
PosOfDecPoint = find('.', tempVar1)
if PosOfDecPoint then
if length(tempVar1)- PosOfDecPoint > multiplier then
multiplier = length(tempVar1)- PosOfDecPoint
end if
end if
PosOfDecPoint = find('.', tempVar2)
if PosOfDecPoint then
if length(tempVar2)- PosOfDecPoint > multiplier then
multiplier = length(tempVar2)- PosOfDecPoint
end if
end if
PosOfDecPoint = find('.', tempVar3)
if PosOfDecPoint then
if length(tempVar3)- PosOfDecPoint > multiplier then
multiplier = length(tempVar3)- PosOfDecPoint
end if
end if
for i = multiplier*var1 to multiplier*var2 by multiplier*var3 do
puts(1, sprint(i/multiplier) & " ")
end for
Dan
----- Original Message -----
From: "Chris Bensler" <bensler at mail.com>
To: "EUforum" <EUforum at topica.com>
Sent: Saturday, March 23, 2002 9:56 PM
Subject: RE: BUG! Erratic for loop behavior
>
> function magnify(atom a)
> sequence str
> integer f
> str = sprintf("%f",a)
> f = find('.',str)
> if f then
> a *= power(10,length(str)-f)
> end if
> return a
> end function
>
> It works for up to 6 decimal places.
> 34.1234567 will not be fully magnified.
>
>
> Chris
>
>
> Dan Moyer wrote:
> > off the top of my head:
> > change the vars to sequence, check for '.', count how many to right of
> > '.',
> > multiply by 10 to the how many for the MAX number in any var?
> >
> > Dan
> >
> > ----- Original Message -----
> > From: "Chris Bensler" <bensler at mail.com>
> > To: "EUforum" <EUforum at topica.com>
> > Sent: Saturday, March 23, 2002 9:02 PM
> > Subject: RE: BUG! Erratic for loop behavior
> >
> >
> > > for i = var1 to var 2 by var3 do
> > > end for
> > >
> > > how much should the vars be multiplied by?
> > >
> > > Chris
> > >
> > > Dan Moyer wrote:
> > > > Andy,
> > > >
> > > > Although I assume this is at least obvious, you could just do this:
> > > >
> > > > for i = 10*31.1 to 10*34.2 do
> > > > ?i/10
> > > > end for
> > > >
> > > > Same for whatever max "level" of floating point you have, ie, if
*any*
> > > > value
> > > > goes out to .001,multiply all by 1000, then divide, etc.
> > > >
> > > > Maybe there's some good reason that doesn't occur to me offhand why
this
> > > > won't work?
> > > >
> > > > Dan Moyer
11. Re: BUG! Erratic for loop behavior
petelomax at blueyonder.co.uk wrote:
>
>
> On Sat, 23 Mar 2002 20:36:14 +0100, Rolf Schröder <r.schr at t-online.de>
> wrote:
>
> >Actually, 0.1 (dec.) is has
> >an unlimited binary representation: 0.0001100110011..... .
>
> Sanity check required. Kinda understand. Kinda appreciate I may have
> been mollycoddled over many years, or somesuch.
>
> Where'd you get this from, please.
>
You do it yourself!
The decimal 0.1 is equal 1/10 . Written with binary numbers it's 1/1010
. Now you fulfill a 'written' division as you may be used to do for
decimal numbers (but now you have only 0 and 1 as digits):
1: 1010 = 0.0001100110011....
-----------
10: 1010 = 0
---------
100 : 1010 = 0
-----------
* 1000 : 1010 = 0
------------
10000 : 1010 = 1
-1010
------
1100 : 1010 = 1
-1010
------
100 : 1010 = 0
----------
1000 : 1010 = 0 from here the same as (*) and therefore
repeated.
One has to become familiar with this kind of calculations :) .
Have a nice division, Rolf
12. Re: BUG! Erratic for loop behavior
Andy,
Got it. I think Kat made a suggestion once for doing "string math" to avoid
this problem in general, don't remember if there was a problem or downside
other than speed. If it's always/only add/subtract dollars & cents, though,
mult/divide
everything that's dollars by 100 should work, but multiplication (like but
not limited to percents) could become a problem, as Chris pointed out that
my solution won't
work for 7 places to right of decimal (his mod of his method works up to 9 I
think).
And I agree that this should be mentioned in the manual, you caught it in
time, others might not, although that brings up the question "who reads the
fine manual?". :)
(actually I refer to it constantly, but that's bad memory at work!)
Dan
----- Original Message -----
From: "Andy Serpa" <renegade at earthling.net>
To: "EUforum" <EUforum at topica.com>
Sent: Saturday, March 23, 2002 10:24 PM
Subject: RE: BUG! Erratic for loop behavior
>
>
> Dan Moyer wrote:
> > Andy,
> >
> > Although I assume this is at least obvious, you could just do this:
> >
> > for i = 10*31.1 to 10*34.2 do
> > ?i/10
> > end for
> >
> > Same for whatever max "level" of floating point you have, ie, if *any*
> > value
> > goes out to .001,multiply all by 1000, then divide, etc.
> >
>
> > Maybe there's some good reason that doesn't occur to me offhand why this
> > won't work?
> >
>
> No, that works fine for getting this particular loop to work. But the
> problem outside of a loop as well. Let's say you make an application
> that adds and subtracts dollars & cents a lot.
>
> .1 + .1 + .1 + .1 + .1 + .1 + .1 + .1 + .1 does not equal 1 -- just try
> it. It will display as one if you print it, but if you do this:
>
> x = .1 + .1 + .1 + .1 + .1 + .1 + .1 + .1 + .1
> if x = 1 then
> puts(1,"TRUE.")
> else
> puts(1,"FALSE.")
> end if
>
> It will come up false.
>
> So if you have a program that does any kind of floating-point
> calculations, and then check to see if a particular value = some other
> value, you'll often get the wrong answer.
>
> I just didn't realize before it was so serious. Those of use who don't
> come from a low-level programming background or don't have a lot of
> hardware knowledge aren't told this anywhere. It really ought to be in
> the manual....
>
>
>
>
13. Re: BUG! Erratic for loop behavior
On Sun, 24 Mar 2002 16:45:00 +0000, Chris Bensler <bensler at mail.com>
wrote:
>This seems like a devastating problem. We use fractional numbers all the
>time. How is it possible that it doesn't show up more often?
>
>Do we need to resort to binary math? Would that even help?
>
>What can be done to ensure that my program is calculating the math
>properly?
>
See http://www2.hursley.ibm.com/decimal/
I think that's what is needed, There is even some C code there.
It is IEEE854 rather than IEEE754.
What does everyone else think?
I should specifically mention the following extracts:
Complaints about the performance of decimal arithmetic are extremely
common. Software emulation is 100 to 1000 times slower than a hardware
implementation could be.
For example, a JIT-compiled 9-digit BigDecimal division in Java takes
over 13,000 clock cycles on an Intel Pentium. Even a simple 9-digit
decimal addition takes at least 1,100 clock cycles. In contrast, a
native hardware decimal type could reduce this to a speed comparable
to binary arithmetic (39 cycles).
Almost all major IBM language products support decimal arithmetic,
including C (as a native data type, on z900), C++ (via libraries),
COBOL, Java (through the Sun or IBM BigDecimal class), OS/400 CL,
PL/I, PL/X (on AS/400), NetRexx, PSM (in DB2), Rexx, Object Rexx, RPG,
and VisualAge Generator. Many other languages also support decimal
arithmetic, including Microsoft’s Visual Basic and C# languages (both
of which provide a floating-point decimal arithmetic using the .Net
runtime Decimal class).
Pete
14. Re: BUG! Erratic for loop behavior
Chris Bensler wrote:
>
> I just did some further testing, and it seems that magnifying a decimal
> value doesn't help either.
>
> ? magnify(0.12345678901) = 12345678901 -- 0
> ? magnify(0.12345678901) = 123456789 -- 0
> ? magnify(0.12345678901) = 12345679 -- 0
>
Chris,
it's the truth for all computer languages: unlimited binary numbers
(like 1/1010) are not exactly representable by floating point numbers.
Be aware there are even more numbers not exactly representable for
calculating machines, like sqrt(2) or exp(1)... . But there are
languages like 'Mathematica' or 'Derive' especially designed to fulfill
so called 'algebraic computations' similar like humans do it after known
rules. But they are slow and not useful for 'number crunching'.
However, for the 'normal' purposes in techniques and science, it's
not necessary to represent numbers exactly, it's sufficient to have a
relative accuracy of 15 decimal digits. All known physical constants do
have only an accuracy of about 4 to 7 decimal digits, not more! But of
course one has to be careful to avoid introducing a loss of accuracy in
calculations, i.e. small differences of large numbers!
You may have always a small loss of accuracy in your programs, Rolf
15. Re: BUG! Erratic for loop behavior
- Posted by jbrown1050 at yahoo.com
Mar 24, 2002
--x+6KMIRAuhnl3hBn
I have a hack which works fairly well, depending on
the accuracy you want.
It is a big hack, and not a long-term solution, but at
least it works.
It works by converting a number to a string and back
again.
Also, it needs a modified get.e, else inf and nan
tests dont work at all.
jbrown
--x+6KMIRAuhnl3hBn
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="test.ex"
-- file which uses a hack to fix problems with
floating-point numbers and nan
include get.e
include misc.e
function num_to_str(atom a)
return sprint(a)
end function
function str_to_num(sequence s)
sequence t
t = value(s)
if t[1] = GET_SUCCESS and atom(t[2]) then
return t[2]
end if
return 0
end function
global function fix_num(atom a)
--this is the hack which "fixes" a number to its
proper value.
a = str_to_num(num_to_str(a))
return a
end function
global constant
inf = 2*power(10, 308),
nan = -(inf/inf)
--test
atom a a = 0
for i = 1 to 10 do
a += .1
end for
? a
? fix_num(a) = 1
a = -(inf/inf)
? a
? fix_num(a) = fix_num(nan) --this doesnt work w/o the
modified get.e
--x+6KMIRAuhnl3hBn
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="get.e"
------------------------------------
-- Input and Conversion Routines: --
-- get() --
-- value() --
-- wait_key() --
------------------------------------
-- needed to check for nan and inf in input data
constant gnan=-(2*power(10,308)/(3*power(10,308))),
ginf=2*power(10,308)
-- error status values returned from get() and
value():
global constant GET_SUCCESS = 0,
GET_EOF = -1,
GET_FAIL = 1
constant M_WAIT_KEY = 26
constant DIGITS = "0123456789",
HEX_DIGITS = DIGITS & "ABCDEF",
START_NUMERIC = DIGITS & "-+.#"
constant TRUE = 1
type natural(integer x)
return x >= 0
end type
type char(integer x)
return x >= -1 and x <= 255
end type
natural input_file -- file to be read from
object input_string -- string to be read from
natural string_next
char ch -- the current character
global function wait_key()
-- Get the next key pressed by the user.
-- Wait until a key is pressed.
return machine_func(M_WAIT_KEY, 0)
end function
procedure get_ch()
-- set ch to the next character in the input stream
(either string or file)
if sequence(input_string) then
if string_next <= length(input_string) then
ch = input_string[string_next]
string_next += 1
else
ch = GET_EOF
end if
else
ch = getc(input_file)
end if
end procedure
procedure skip_blanks()
-- skip white space
-- ch is "live" at entry and exit
while find(ch, " \t\n\r") do
get_ch()
end while
end procedure
constant ESCAPE_CHARS = "nt'\"\\r",
ESCAPED_CHARS = "\n\t'\"\\\r"
function escape_char(char c)
-- return escape character
natural i
i = find(c, ESCAPE_CHARS)
if i = 0 then
return GET_FAIL
else
return ESCAPED_CHARS[i]
end if
end function
function get_qchar()
-- get a single-quoted character
-- ch is "live" at exit
char c
get_ch()
c = ch
if ch = '\\' then
get_ch()
c = escape_char(ch)
if c = GET_FAIL then
return {GET_FAIL, 0}
end if
elsif ch = '\'' then
return {GET_FAIL, 0}
end if
get_ch()
if ch != '\'' then
return {GET_FAIL, 0}
else
get_ch()
return {GET_SUCCESS, c}
end if
end function
function get_string()
-- get a double-quoted character string
-- ch is "live" at exit
sequence text
text = ""
while TRUE do
get_ch()
if ch = GET_EOF or ch = '\n' then
return {GET_FAIL, 0}
elsif ch = '"' then
get_ch()
return {GET_SUCCESS, text}
elsif ch = '\\' then
get_ch()
ch = escape_char(ch)
if ch = GET_FAIL then
return {GET_FAIL, 0}
end if
end if
text = text & ch
end while
end function
type plus_or_minus(integer x)
return x = -1 or x = +1
end type
function get_number()
-- read a number
-- ch is "live" at entry and exit
plus_or_minus sign, e_sign
natural ndigits
integer hex_digit
atom mantissa, dec, e_mag
sign = +1
mantissa = 0
ndigits = 0
-- process sign
if ch = '-' then
sign = -1
get_ch()
elsif ch = '+' then
get_ch()
end if
if ch = 'n' then
get_ch()
if ch = 'a' then
get_ch()
if ch = 'n' then
return {GET_SUCCESS, gnan*sign}
else
return {GET_FAIL, 0}
end if
else
return {GET_FAIL, 0}
end if
end if
if ch = 'i' then
get_ch()
if ch = 'n' then
get_ch()
if ch = 'f' then
return {GET_SUCCESS, ginf*sign}
else
return {GET_FAIL, 0}
end if
else
return {GET_FAIL, 0}
end if
end if
-- get mantissa
if ch = '#' then
-- process hex integer and return
get_ch()
while TRUE do
hex_digit = find(ch, HEX_DIGITS)-1
if hex_digit >= 0 then
ndigits += 1
mantissa = mantissa * 16 + hex_digit
get_ch()
else
if ndigits > 0 then
return {GET_SUCCESS, sign * mantissa}
else
return {GET_FAIL, 0}
end if
end if
end while
end if
-- decimal integer or floating point
while ch >= '0' and ch <= '9' do
ndigits += 1
mantissa = mantissa * 10 + (ch - '0')
get_ch()
end while
if ch = '.' then
-- get fraction
get_ch()
dec = 10
while ch >= '0' and ch <= '9' do
ndigits += 1
mantissa += (ch - '0') / dec
dec *= 10
get_ch()
end while
end if
if ndigits = 0 then
return {GET_FAIL, 0}
end if
mantissa = sign * mantissa
if ch = 'e' or ch = 'E' then
-- get exponent sign
e_sign = +1
e_mag = 0
get_ch()
if ch = '-' then
e_sign = -1
get_ch()
elsif ch = '+' then
get_ch()
end if
-- get exponent magnitude
if ch >= '0' and ch <= '9' then
e_mag = ch - '0'
get_ch()
while ch >= '0' and ch <= '9' do
e_mag = e_mag * 10 + ch - '0'
get_ch()
end while
else
return {GET_FAIL, 0} -- no exponent
end if
e_mag *= e_sign
if e_mag > 308 then
-- rare case: avoid power() overflow
mantissa *= power(10, 308)
if e_mag > 1000 then
e_mag = 1000
end if
for i = 1 to e_mag - 308 do
mantissa *= 10
end for
else
mantissa *= power(10, e_mag)
end if
end if
return {GET_SUCCESS, mantissa}
end function
function Get()
-- read a Euphoria data object as a string of
characters
-- and return {error_flag, value}
-- Note: ch is "live" at entry and exit of this
routine
sequence s, e
skip_blanks()
if find(ch, START_NUMERIC) then
return get_number()
elsif ch = '{' then
-- process a sequence
s = {}
get_ch()
skip_blanks()
if ch = '}' then
get_ch()
return {GET_SUCCESS, s} -- empty sequence
end if
while TRUE do
e = Get() -- read next element
if e[1] != GET_SUCCESS then
return e
end if
s = append(s, e[2])
skip_blanks()
if ch = '}' then
get_ch()
return {GET_SUCCESS, s}
elsif ch != ',' then
return {GET_FAIL, 0}
end if
get_ch() -- skip comma
end while
elsif ch = '\"' then
return get_string()
elsif ch = '\'' then
return get_qchar()
elsif ch = -1 then
return {GET_EOF, 0}
else
return {GET_FAIL, 0}
end if
end function
global function get(integer file)
-- Read the string representation of a Euphoria object
-- from a file. Convert to the value of the object.
-- Return {error_status, value}.
input_file = file
input_string = 0
get_ch()
return Get()
end function
global function value(sequence string)
-- Read the representation of a Euphoria object
-- from a sequence of characters. Convert to the value
of the object.
-- Return {error_status, value).
input_string = string
string_next = 1
get_ch()
return Get()
end function
global function prompt_number(sequence prompt,
sequence range)
-- Prompt the user to enter a number.
-- A range of allowed values may be specified.
object answer
while 1 do
puts(1, prompt)
answer = gets(0) -- make sure whole line is read
puts(1, '\n')
answer = value(answer)
if answer[1] != GET_SUCCESS or sequence(answer[2])
then
puts(1, "A number is expected - try again\n")
else
if length(range) = 2 then
if range[1] <= answer[2] and answer[2] <= range[2]
then
return answer[2]
else
printf(1,
"A number from %g to %g is expected here - try
again\n",
range)
end if
else
return answer[2]
end if
end if
end while
end function
global function prompt_string(sequence prompt)
-- Prompt the user to enter a string
object answer
puts(1, prompt)
answer = gets(0)
puts(1, '\n')
if sequence(answer) and length(answer) > 0 then
return answer[1..length(answer)-1] -- trim the \n
else
return ""
end if
end function
global function get_bytes(integer fn, integer n)
-- Return a sequence of n bytes (maximum) from an open
file.
-- If n > 0 and fewer than n bytes are returned,
-- you've reached the end of file.
-- This function is normally used with files opened in
binary mode.
sequence s
integer c
if n = 0 then
return {}
end if
c = getc(fn)
if c = -1 then
return {}
end if
s = repeat(c, n)
for i = 2 to n do
s[i] = getc(fn)
end for
if s[n] != -1 then
return s
else
-- trim eof's
while s[n] = -1 do
n -= 1
end while
return s[1..n]
end if
end function
-- This file (unless modified) is FREE - 0 statements.
--with 234268341 -- delete this statement if it causes
an error
--x+6KMIRAuhnl3hBn--
16. Re: BUG! Erratic for loop behavior
dm31 at uow.edu.au wrote:
> ...
> an example is the 0.1 is stored as 1 x 10^-1
> thus the mantissa is 1 and the exponent is -1
> ...
That's not the truth! Mantissa and exponent each are stored as BINARY
numbers, NOT decimal!
o.1 decimal is binary (unlimited):
0.000110011001100... which is stored as 0.110011001100... -1000 ,
(mantissa) (exponent)
the usual way to store floating point numbers.
Note: the mantissa is cut due to the limited number of bytes available;
it means not exactly!
Look here for more details:
http://www.psc.edu/general/software/packages/ieee/ieee.html
Have a nice day, Rolf
17. Re: BUG! Erratic for loop behavior
On Mon, 25 Mar 2002 11:04:25 +1000, dm31 at uow.edu.au wrote:
>an example is the 0.1 is stored as 1 x 10^-1
>thus the mantissa is 1 and the exponent is -1
>so using a 8-bit float as an example 0.1 in binary is
>
>0001 and 1111(-1 in 2's complement)
>
>So storing numbers like 0.1, 0.3 and 0.01 completely accurately should
>not be a problem. It is only a problem in 'larger' decimal numbers.
>
>for i = 31.4 to 31.5 do... should work perfectly. Or am I just been
>dumb?
Possibly the latter
IEEE 754 floating point numbers are held in
binary math, ie <sign>*<mantissa>*2^<exponent>.
Yes, that's powers of 2, not 10. This means that 0.1 *CANNOT* be held,
the closest you get is about 0.100000000149
Read all about the only alternative I've found at
http://www2.hursley.ibm.com/decimal/
Pete