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.

new topic     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

4. Re: BUG! Erratic for loop behavior

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"?
> >
> >
>
>
>

new topic     » goto parent     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

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=

new topic     » goto parent     » topic index » view message » categorize

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.
>

new topic     » goto parent     » topic index » view message » categorize

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.
> > >
> >
>
>
>

new topic     » goto parent     » topic index » view message » categorize

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.
> > > >
> > >

new topic     » goto parent     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

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....
>
>
>
>

new topic     » goto parent     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

15. Re: BUG! Erratic for loop behavior

--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--

new topic     » goto parent     » topic index » view message » categorize

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

new topic     » goto parent     » topic index » view message » categorize

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 blink  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

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu