FORTRAN floating point accuracy problems
04-11-2016, 12:35 PM
Post: #41
 Werner Senior Member Posts: 315 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
(04-11-2016 12:03 PM)Dieter Wrote:  In this case Excel indeed returns 20 for INT(100*dms).

Indeed it does.. but it's an example of Excel 'fiddling' - it adjusted the results to match its decimal audience ;-)

Free42 Binary returns 20 only with 1e16 - because then 5e16 + 1 equals 5e16.
Excel really should use decimal arithmetic..

Cheers, Werner
04-12-2016, 06:48 PM
Post: #42
 Dieter Senior Member Posts: 2,076 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
(04-11-2016 12:35 PM)Werner Wrote:
(04-11-2016 12:03 PM)Dieter Wrote:  In this case Excel indeed returns 20 for INT(100*dms).

Indeed it does.. but it's an example of Excel 'fiddling' - it adjusted the results to match its decimal audience ;-)
(...)
Excel really should use decimal arithmetic..

Well, Excel and mathematics... that's two different worlds. Especially as far as more advanced functions are concerned. I remember how older versions handled the Normal quantile function – the results were inaccurate (about 5 digits) and below a certain limit the result simply was... ±500000. *facepalm*

(04-11-2016 12:35 PM)Werner Wrote:  Free42 Binary returns 20 only with 1e16 - because then 5e16 + 1 equals 5e16.

Hmm....
Free42 Binary uses standard IEEE754 double precision and the computer's FPU, that's 16 valid digits at best.
Now 1E15/(5E15+1) = 0,19999 99999 99999 960000..., which, even when rounded to 16 digits, equals 0,2.
If IP(100*this) is 19, this of course is mathematically correct. But does Free42 Binary display 100x the above fraction as 19,999... or 20? So does it display 20 and at the same time return 19 as the integer portion of this?

Things like these are the reason why I prefer Free42 Decimal. ;-)

Dieter
04-13-2016, 06:23 AM
Post: #43
 Werner Senior Member Posts: 315 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
1E15/(5E15 +1) on Free42 Bin equals (hex digits

1.9999999999998 * 2^(-3)

In the display of course, this shows as 0.2, but after

1e8 x FP

you see

9.99999996275e-1

And the '6' in its decimal representation is really the 16th digit, not the 17th (the leading '1' is the implied bit, not a full digit), it doesn't get rounded.

When you enter 0.2, it's hex representation is

1.999999999999A * 2^(-3)

Cheers, Werner
04-14-2016, 08:18 AM
Post: #44
 EdS2 Member Posts: 96 Joined: Apr 2014
RE: FORTRAN floating point accuracy problems
I don't think binary arithmetic is to blame here - rather, it's the lack of a true conversion to integer. Either truncation or rounding would be fine, so long as they are accurate to all digits. The problem here is a little extra "cosmetic" rounding which seems to be difficult or impossible to avoid.

It might be OK if you take the integer part and then check by subtraction that it's the right value - now you have a program instead of a formula.
04-19-2016, 06:39 AM
Post: #45
 HP67 Senior Member Posts: 554 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
Guys I have been preparing for a big holiday coming up so I haven't been able to get back to this thread. I am still interested and will be able to update in a few weeks. Sorry for the delay and thanks for all your comments and suggestions.

It ain't OVER 'till it's 2 PICK
05-03-2016, 11:54 AM
Post: #46
 HP67 Senior Member Posts: 554 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
Ok guys, I am almost back. Dieter, do you have an idea how to proceed now that we have your rounding function available?

Anybody else, ideas I should try? I'll go over the thread again since I have forgotten where we left off.

Thanks.

It ain't OVER 'till it's 2 PICK
05-03-2016, 12:47 PM
Post: #47
 Dieter Senior Member Posts: 2,076 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
(05-03-2016 11:54 AM)HP67 Wrote:  Ok guys, I am almost back. Dieter, do you have an idea how to proceed now that we have your rounding function available?

Using the rounding function you could try something like this:

Code:
Function dms2dd(dms) Const safedigits = 15  ' or in your case: 16 dd = Int(dms) If dms > 1 Then    k = Int(log10(dd))    ' I assume Fortran features an exact log10 function Else    k = 0 End If n = safedigits - 3 - k mmss = Round(100 * (dms - dd), n) mm = Int(mmss) ss = (mmss - mm) * 100 dms2dd = dd + mm / 60 + ss / 3600 End Function

Here "safedigits" is the number of significant decimals we can consider exact. That's 15 for IEEE754 DP and 16 in your case.

The algorithm essentially determines how many digits after the decimal point can be assumed exact (15 resp. 16 minus the number of digits of the integer part) and rounds the mm.ss part accordingly.

Dieter
05-03-2016, 01:02 PM (This post was last modified: 05-03-2016 01:04 PM by HP67.)
Post: #48
 HP67 Senior Member Posts: 554 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
Thanks, I'll try this and post back when I can.

It would be nice if there were some way of determining safedigits environmentally, without having to code a constant, so the code would be somewhat portable.

It ain't OVER 'till it's 2 PICK
05-03-2016, 02:56 PM
Post: #49
 Dieter Senior Member Posts: 2,076 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
(05-03-2016 01:02 PM)HP67 Wrote:  It would be nice if there were some way of determining safedigits environmentally, without having to code a constant, so the code would be somewhat portable.

Some languages feature a function that returns the smalles possible machine epsilon. Others could use something like this:

Code:
Function safedigits() e = 1.0   ' e has the data type for which we want to know the number of valid decimal digits Do While 1.0 + e > 1.0    e = e * 0.5 Loop safedigits = Int(-Log10(e)) End Function

However, things may be slightly different with base-16 encoded numbers like the ones used by your hardware: cf. here.

Dieter
05-04-2016, 11:05 AM
Post: #50
 HP67 Senior Member Posts: 554 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
Code:
 T1DMS2DD  TEST          DMS       EXPECT       RESULT         DIFF     1   89.1115000   89.1875000   89.1875000    0.0000000     2   12.1500000   12.2500000   12.2500000    0.0     3   33.3000000   33.5000000   33.5000000    0.0     4   71.0030000   71.0083333   71.0083333    0.0000000     5   42.2453000   42.4147222   42.4147222    0.0000000     6   38.4225000   38.7069444   38.7069444    0.0000000     7   29.3030000   29.5083333   29.5083333    0.0000000     8    0.4949000    0.8302777    0.8302778    0.0000001     9   75.1500000   75.2500000   75.2500000    0.0    10   43.2230000   43.3750000   43.3750000    0.0000000    11    9.3345000    9.5625000    9.5625000    0.0000000    12   33.5752200   33.9645000   33.9645000    0.0    13   13.0724420   13.1234500   13.1234500    0.0000000    14   21.3000000   21.5000000   21.5000000    0.0    15   59.4721120   59.7892000   59.7892000    0.0    16   65.1100960   65.1836000   65.1836000    0.0000000

Outstanding! Thanks, Dieter!

I'll get back to you on how I made out with your program that calculates the epsilon later.

It ain't OVER 'till it's 2 PICK
05-04-2016, 01:34 PM (This post was last modified: 05-04-2016 02:05 PM by Dieter.)
Post: #51
 Dieter Senior Member Posts: 2,076 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
(05-04-2016 11:05 AM)HP67 Wrote:  Outstanding! Thanks, Dieter!

Fine. There is just one issue: if the input is very small, i.e. dms is a fraction of a second, or maybe even something below 1E–16, the input may be rounded down to zero. This can be avoided by replacing the respective lines by this:

Code:
If dms >= 1 Then    k = int(log10(dms)) Else    k = int(log10(dms)) - 1 End If

If there was a FLOOR function the test was not required at all: k=FLOOR(log10(dms).
Maybe you can write one in Assembler. ;-)

Now add a few lines that handle dms<0 (there is a DSIGN function in Fortran IV) or dms=0 (simply return zero), and you're done.

Edit: this could be a solution.

Code:
Function dms2dd(dms) Const safedigits = 16 adms = Abs(dms) If adms >= 1 Then    k = Int(log10(adms)) Else    If adms = 0 Then       k = 0    Else       k = Int(log10(adms)) - 1    End If End If n = safedigits - 3 - k dd = Int(adms) mmss = Round(100 * (adms - dd), n) mm = Int(mmss) ss = (mmss - mm) * 100 dms2dd = dsign(dd + mm / 60 + ss / 3600, dms) End Function

If I get it right, dsign transfers the sign of the second argument to the first one, i.e. dsgn(x, y) = abs(x) * sign(y), which is quite handy here.

Dieter
05-04-2016, 02:50 PM (This post was last modified: 05-04-2016 02:52 PM by HP67.)
Post: #52
 HP67 Senior Member Posts: 554 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
(05-04-2016 01:34 PM)Dieter Wrote:  Fine. There is just one issue: if the input is very small, i.e. dms is a fraction of a second, or maybe even something below 1E–16, the input may be rounded down to zero. This can be avoided by replacing the respective lines by this:

Code:
If dms >= 1 Then    k = int(log10(dms)) Else    k = int(log10(dms)) - 1 End If

If there was a FLOOR function the test was not required at all: k=FLOOR(log10(dms).
Maybe you can write one in Assembler. ;-)

Actually I had a FLOOR function in FORTRAN that was based on the less than optimal IDINT function that I replaced with my handy-dandy assembler DINT. So this is available now. This is what I have been using, does it look ok or can it be improved:

Code:
       DOUBLE PRECISION FUNCTION DFLOOR(X)                               00040003       REAL*8 X                                                          00050000       REAL*8 DINT                                                       00070004 C                                                                       00080004       DFLOOR = DINT(X)                                                  00090004       IF (X .LT. 0.0D0) DFLOOR = DFLOOR - 1.0D0                         00100002       RETURN                                                            00110000       END                                                               00120000

(05-04-2016 01:34 PM)Dieter Wrote:  Now add a few lines that handle dms<0 (there is a DSIGN function in Fortran IV) or dms=0 (simply return zero), and you're done.

Edit: this could be a solution.

Code:
Function dms2dd(dms) Const safedigits = 16 adms = Abs(dms) If adms >= 1 Then    k = Int(log10(adms)) Else    If adms = 0 Then       k = 0    Else       k = Int(log10(adms)) - 1    End If End If n = safedigits - 3 - k dd = Int(adms) mmss = Round(100 * (adms - dd), n) mm = Int(mmss) ss = (mmss - mm) * 100 dms2dd = dsign(dd + mm / 60 + ss / 3600, dms) End Function

If I get it right, dsign transfers the sign of the second argument to the first one, i.e. dsgn(x, y) = abs(x) * sign(y), which is quite handy here.

Dieter

Given our beautiful results above is this necessary? If you think it's a good idea I'll look into that later since I have shut the machine off already.

Thanks again.

It ain't OVER 'till it's 2 PICK
05-04-2016, 06:04 PM
Post: #53
 Dieter Senior Member Posts: 2,076 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
(05-04-2016 02:50 PM)HP67 Wrote:  Actually I had a FLOOR function in FORTRAN that was based on the less than optimal IDINT function that I replaced with my handy-dandy assembler DINT. So this is available now. This is what I have been using, does it look ok or can it be improved:

It can be improved so that it returns correct results for integer x<0. The given implementation will return FLOOR(–3) = –4, which of course is wrong. You might test if x<0 and x≠int(x).

(05-04-2016 02:50 PM)HP67 Wrote:  Given our beautiful results above is this necessary?

The suggested changes provide correct results for arguments that are extremely small, zero or negative. I think this makes sense.

Dieter
06-04-2016, 06:42 PM
Post: #54
 HP67 Senior Member Posts: 554 Joined: Dec 2013
RE: FORTRAN floating point accuracy problems
Thanks. I have no idea how I could have missed that. Something looked wrong to me. Fixed!

I'll get back to the other improvements asap but have been unable to get back to this for a long time since some big things have been going on.

It ain't OVER 'till it's 2 PICK
 « Next Oldest | Next Newest »

User(s) browsing this thread: 1 Guest(s)