Re: [Tutor] the binary math "wall"

2010-04-25 Thread Lowell Tackett

>From the virtual desk of Lowell Tackett  



--- On Tue, 4/20/10, Steven D'Aprano  wrote:

> From: Steven D'Aprano 
> Subject: Re: [Tutor] the binary math "wall"
> To: tutor@python.org
> Date: Tuesday, April 20, 2010, 7:39 PM
> On Wed, 21 Apr 2010 02:58:06 am
> Lowell Tackett wrote:
> > I'm running headlong into the dilemma of binary math
> representation, 
> with game-ending consequences, e.g.:
> > >>> 0.15

> But if you really need D.MMSS floats, then something like
> this should be 
> a good start.:
> 
> def dms2deg(f):
> """Convert a floating point number formatted
> as D.MMSS 
> into degrees.
> """
> mmss, d = math.modf(f)
> assert d == int(f)
> if mmss >= 0.60:
> raise ValueError(
> 'bad fractional part, expected
> < .60 but got %f' % mmss)
> mmss *= 100
> m = round(mmss)
> if m >= 60:
> raise ValueError('bad minutes,
> expected < 60 but got %d' % m)
> s = round((mmss - m)*100, 8)
> if not 0 <= s < 60.0:
> raise ValueError('bad seconds,
> expected < 60.0 but got %f' % s)
> return d + m/60.0 + s/3600.0
> 
> 
> >>> dms2deg(18.15)
> 18.25
> >>> dms2deg(18.1515)
> 18.2541666
> 
> 

Haven't gone away...I'm having a blast dissecting (parsing[?]-is that the right 
word?) your script snippet!  Got a big pot of coffee fueling the effort.

> 
> Note though that this still fails with some valid input. I
> will leave 
> fixing it as an exercise (or I might work on it later, time
> 
> permitting).

Got the hint...I'm gonna pick up this challenge.  This effort is taking me in 
endless tangents (all productive)-I'll be back sometime [soon] with my efforts 
and results.  Thanks for your [own] time and effort.

> 
> 
> -- 
> Steven D'Aprano
> ___
> Tutor maillist  -  Tutor@python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
> 


  

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread Dave Angel

Steven D'Aprano wrote:

On Thu, 22 Apr 2010 01:37:35 am Lowell Tackett wrote:



Were I to accumulate many of these "legs" into perhaps a 15 mile
traverse-accumulating little computer errors along the way-the end
result could be catastrophically wrong.



YES!!! 

And just by being aware of this potential problem, you are better off 
than 90% of programmers who are blithely unaware that floats are not 
real numbers.



  
Absolutely.  But "catastrophically wrong" has to be defined, and 
analyzed.  If each of these measurements is of 100 feet, measured to an 
accuracy of .0001 feet, and you add up the measurements in Python 
floats, you'll be adding 750 measurements, and your human error could 
accumulate to as much as .07 feet.


The same 750 floating point ads, each to 15 digits of quantization 
accuracy (thanks for the correction, it isn't 18) will give a maximum 
"computer error" of  maybe .1 feet.  The human error is much 
larger than the computer error.


No results can be counted on without some analysis of both sources of 
error.  Occasionally, the "computer error" will exceed the human, and 
that depends on the calculations you do on your measurements.


HTH,
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread Steven D'Aprano
On Thu, 22 Apr 2010 01:37:35 am Lowell Tackett wrote:

> Recalling (from a brief foray into college Chem.) that a result could
> not be displayed with precision greater than the least precise
> component that bore [the result].  So, yes, I could accept my input
> as the arbitrator of accuracy.

Unfortunately, you can't distinguish the number of supplied digits of 
accuracy from a float. Given as floats, all of the following are 
identical:

0.1
0.1
0.09
0.11

as are these two:

0.08
0.099985

Perhaps you should look at the Decimal class, not necessarily to use it, 
but to see what they do. For instance, you create a Decimal with a 
string, not a float:

>>> from decimal import Decimal
>>> Decimal('0.1')
Decimal("0.1")
>>> Decimal('0.1')
Decimal("0.1")

which allows you to distinguish the number of digits of precision.


> A scenario:
>
> Calculating the coordinates of a forward station from a given base
> station would require [perhaps] the bearing (an angle from north,
> say) and distance from hither to there.  Calculating the north
> coordinate would set up this relationship, e.g.:
>
> cos(3° 22' 49.6") x 415.9207'(Hyp) = adjacent side(North)
>
> My first requirement, and this is the struggle I (we) are now engaged
> in, is to convert my bearing angle (3° 22' 49.6") to decimal degrees,
> such that I can assign its' proper cosine value.

This is MUCH MUCH MUCH easier than trying to deal with DMS as a float. 
Your data already separates the parts for you, so it is just a matter 
of:

>>> d = 3 + 22/60.0 + 49.2/3600.0
>>> import math
>>> angle = math.radians(d)
>>> math.cos(angle)
0.9982601259166638

Then the only problem you have is whether or not the formula you are 
using is numerically stable, or whether it is subject to 
catastrophically growing errors.

I hope we're not frightening you off here. For nearly anything people 
are going to want to do, their input data will be in single-precision. 
One of the simplest things they can do to improve the accuracy of 
floating point calculations is to do their intermediate calculations in 
double-precision.

The good news is, Python floats are already in double-precision.

For most modern systems, single-precision floats have 24 binary digits 
of precision (approximately 6 decimal digits) and double-precision 
floats have 53 binary digits (15 decimal) of precision. More than 
sufficient for dealing with an angle measured to a tenth of a second.


Some resources for you to read:

http://en.wikipedia.org/wiki/Floating_point
http://www.cs.princeton.edu/introcs/91float/
http://www.cs.berkeley.edu/~wkahan/
http://docs.sun.com/source/806-3568/ncg_goldberg.html



> Were I to accumulate many of these "legs" into perhaps a 15 mile
> traverse-accumulating little computer errors along the way-the end
> result could be catastrophically wrong.

YES!!! 

And just by being aware of this potential problem, you are better off 
than 90% of programmers who are blithely unaware that floats are not 
real numbers.




-- 
Steven D'Aprano
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread Ricardo Aráoz
Lowell Tackett wrote:
> >From the virtual desk of Lowell Tackett  
>
>
>
> --- On Wed, 4/21/10, Dave Angel  wrote:
>
>   
>> From: Dave Angel 
>> Subject: Re: [Tutor] the binary math "wall"
>> To: "Lowell Tackett" 
>> Cc: tutor@python.org, "Steven D'Aprano" 
>> Date: Wednesday, April 21, 2010, 12:31 PM
>> Lowell Tackett wrote:
>> 
>>> From the virtual desk of Lowell Tackett  
>>>
>>>
>>>   
> *Whole buncha stuff snipped*
>   
>> Anyway, in your case binary floating point is
>> irrelevant.  You've got to do your own error analysis
>> of every step in the calculation to understand how much you
>> can trust the result.  And it's unlikely the "errors"
>> in the math package will be the limiting factor.
>>
>> DaveA
>>
>>
>> 
>
> The sense of all this is beginning to emerge (perhaps).  Emile has just made 
> a good point, simply convert all to whole values (using a subset algorithm 
> that keeps track of the number of decimal "slips" that have accumulated-for 
> later reconversion), crunch merrily away, and get good results.
>
> Maybe that's valid, maybe not.  But I do know that this much is happening; 
> I'm now beginning to quantify very novel and wide ranging ideas way outside 
> "the box" I'd originally approached the challenge with.  That's the bigger 
> value of this entire exercise, I think.  Naively thinking that the computer 
> was benign and forgiving, I'd first opted for the most transparent and 'at 
> hand' solutions...there was much to be learned.
>
> I know a coupla things now...I'm gonna solve this dilemma, and largely with 
> the help of all who've weighed in.   The solution may ultimately not be close 
> to what has been suggested, but isn't that the fun of it all?
>
> Secondly, there has accumulated [here] quite an array of novel (to me) 
> thinking that I'm going to return to more and more as I tackle other, 
> different projects, for the pedagogical value that will linger.
>   

Check python help docs for module decimal, there you have an example on
how to code a sin() and cos() functions with arbitrary precision
(depends on your context precision) using decimal values. Might be what
you are looking for (of course you would have to express your angles in
radians throughout all of your calculations and if needed convert at the
end.

HTH

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread Lowell Tackett

>From the virtual desk of Lowell Tackett  



--- On Wed, 4/21/10, Dave Angel  wrote:

> From: Dave Angel 
> Subject: Re: [Tutor] the binary math "wall"
> To: "Lowell Tackett" 
> Cc: tutor@python.org, "Steven D'Aprano" 
> Date: Wednesday, April 21, 2010, 12:31 PM
> Lowell Tackett wrote:
> > From the virtual desk of Lowell Tackett  
> > 
> > 
*Whole buncha stuff snipped*
> 
> Anyway, in your case binary floating point is
> irrelevant.  You've got to do your own error analysis
> of every step in the calculation to understand how much you
> can trust the result.  And it's unlikely the "errors"
> in the math package will be the limiting factor.
> 
> DaveA
> 
> 

The sense of all this is beginning to emerge (perhaps).  Emile has just made a 
good point, simply convert all to whole values (using a subset algorithm that 
keeps track of the number of decimal "slips" that have accumulated-for later 
reconversion), crunch merrily away, and get good results.

Maybe that's valid, maybe not.  But I do know that this much is happening; I'm 
now beginning to quantify very novel and wide ranging ideas way outside "the 
box" I'd originally approached the challenge with.  That's the bigger value of 
this entire exercise, I think.  Naively thinking that the computer was benign 
and forgiving, I'd first opted for the most transparent and 'at hand' 
solutions...there was much to be learned.

I know a coupla things now...I'm gonna solve this dilemma, and largely with the 
help of all who've weighed in.   The solution may ultimately not be close to 
what has been suggested, but isn't that the fun of it all?

Secondly, there has accumulated [here] quite an array of novel (to me) thinking 
that I'm going to return to more and more as I tackle other, different 
projects, for the pedagogical value that will linger.


  

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread Dave Angel

Lowell Tackett wrote:
From the virtual desk of Lowell Tackett  




--- On Wed, 4/21/10, Dave Angel  wrote:

  

From: Dave Angel 
Subject: Re: [Tutor] the binary math "wall"
To: "Lowell Tackett" 
Cc: tutor@python.org, "Steven D'Aprano" 
Date: Wednesday, April 21, 2010, 6:46 AM


Lowell Tackett wrote:


--- On Tue, 4/20/10, Steven D'Aprano 
  

wrote:

  
  

From: Steven D'Aprano 


The simplest, roughest way...hit them with a
hammer:



round(18.15*100) == 1815
  
  
   


True



...when I tried...:

Python 2.5.1 (r251:54863, Oct 14 2007, 12:51:35)
[GCC 3.4.1 (Mandrakelinux 10.1 3.4.1-4mdk)] on linux2
Type "help", "copyright", "credits" or "license" for
  

more information.

  
  

round(18.15)*100 == 1815



False
  

  

But you typed it differently than Steven.  He
had   round(18.15*100), and you used
round(18.15)*100



As soon as I'd posted my answer I realized this mistake.

  

Very different.   His point boils down to
comparing integers, and when you have dubious values, round
them to an integer before comparing.  I have my doubts,
since in this case it would lead to bigger sloppiness than
necessary.

round(18.154 *100) == 1815

probably isn't what you'd want.

So let me ask again, are all angles a whole number of
seconds?  Or can you make some assumption about how
accurate they need to be when first input (like tenths of a
second, or whatever)?  If so use an integer as
follows:

val =  rounddegrees*60)+minutes)*60) +
seconds)*10)

The 10 above is assuming that tenths of a second are your
quantization.

HTH
DaveA





Recalling (from a brief foray into college Chem.) that a result could not be 
displayed with precision greater than the least precise component that bore 
[the result].  So, yes, I could accept my input as the arbitrator of accuracy.

A scenario:

Calculating the coordinates of a forward station from a given base station 
would require [perhaps] the bearing (an angle from north, say) and distance 
from hither to there.  Calculating the north coordinate would set up this 
relationship, e.g.:

cos(3° 22' 49.6") x 415.9207'(Hyp) = adjacent side(North)

My first requirement, and this is the struggle I (we) are now engaged in, is to 
convert my bearing angle (3° 22' 49.6") to decimal degrees, such that I can 
assign its' proper cosine value.  Now, I am multiplying these two very refined 
values (yes, the distance really is honed down to 10,000'ths of a foot-that's normal 
in surveying data); within the bowels of the computer's blackboard scratch-pad, I 
cannot allow errors to evolve and emerge.

Were I to accumulate many of these "legs" into perhaps a 15 mile 
traverse-accumulating little computer errors along the way-the end result could be 
catastrophically wrong.

(Recall that in the great India Survey in the 1800's, Waugh got the elevation of Mt. 
Everest wrong by almost 30' feet for just this exact same reason.)  In surveying, we have 
a saying, "Measure with a micrometer, mark with chalk, cut with an axe".  
Accuracy [in math] is a sacred tenet.

So, I am setting my self very high standards of accuracy, simply because those 
are the standards imposed by the project I am adapting, and I can require 
nothing less of my finished project.

  
If you're trying to be accurate when calling cos, why are you using 
degrees?  The cosine function takes an angle in radians.  So what you 
need is a method to convert from deg/min/sec to radians.  And once you 
have to call trig, you can throw out all the other nonsense about 
getting exact values.  Trig functions don't take arbitrary number 
units.  They don't take decimals, and they don't take fractions.  They 
take double-precision floats.


Perhaps you don't realize the amount of this quantization error we've 
been talking about.  The double type is 64bits in size, and contains the 
equivalent of about 18 decimal digits of precision.  (Assuming common 
modern architectures, of course)



Your angle is specified to about 5 digits of precision, and the distance 
to 7.  So it would take a VERY large number of typical calculations for 
errors in the 18th place to accumulate far enough to affect those.


The real problem, and one that we can't solve for you, and neither can 
Python, is that it's easy to do calculations starting with 8 digits of 
accuracy, and the result be only useful to 3 or 4.  For example, simply 
subtract two very close numbers, and use the result as though it were 
meaningful.


I once had a real customer send us a letter asking about the math 
precision of a calculation he was doing.  I had written the math 
microcode of the machine he was using (from add and subtract, up to 
trigs and logs, I

Re: [Tutor] the binary math "wall"

2010-04-21 Thread Emile van Sebille

On 4/21/2010 8:37 AM Lowell Tackett said...


So, I am setting my self very high standards of accuracy,
simply because those are the standards imposed by the project
I am adapting, and I can require nothing less of my finished project.


Then keep the source data in tenths (or 100ths or 1000ths) as whole 
numbers and only convert upon presentation and your calculations will 
always be accurate for the source measurements taken.


In accounting systems I've always keep dollar amounts in whole pennies 
for this same reason.


Emile



___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread Lowell Tackett

>From the virtual desk of Lowell Tackett  



--- On Wed, 4/21/10, Dave Angel  wrote:

> From: Dave Angel 
> Subject: Re: [Tutor] the binary math "wall"
> To: "Lowell Tackett" 
> Cc: tutor@python.org, "Steven D'Aprano" 
> Date: Wednesday, April 21, 2010, 6:46 AM
> 
> 
> Lowell Tackett wrote:
> > --- On Tue, 4/20/10, Steven D'Aprano 
> wrote:
> > 
> >   
> >> From: Steven D'Aprano 
> >> 
> >> 
> >> The simplest, roughest way...hit them with a
> >> hammer:
> >> 
> >>>>> round(18.15*100) == 1815
> >>>>>   
>
> >> True
> >> 
> > 
> > ...when I tried...:
> > 
> > Python 2.5.1 (r251:54863, Oct 14 2007, 12:51:35)
> > [GCC 3.4.1 (Mandrakelinux 10.1 3.4.1-4mdk)] on linux2
> > Type "help", "copyright", "credits" or "license" for
> more information.
> >   
> >>>> round(18.15)*100 == 1815
> >>>> 
> > False
> >   
> > 
> But you typed it differently than Steven.  He
> had   round(18.15*100), and you used
> round(18.15)*100

As soon as I'd posted my answer I realized this mistake.

> 
> Very different.   His point boils down to
> comparing integers, and when you have dubious values, round
> them to an integer before comparing.  I have my doubts,
> since in this case it would lead to bigger sloppiness than
> necessary.
> 
> round(18.154 *100) == 1815
> 
> probably isn't what you'd want.
> 
> So let me ask again, are all angles a whole number of
> seconds?  Or can you make some assumption about how
> accurate they need to be when first input (like tenths of a
> second, or whatever)?  If so use an integer as
> follows:
> 
> val =  rounddegrees*60)+minutes)*60) +
> seconds)*10)
> 
> The 10 above is assuming that tenths of a second are your
> quantization.
> 
> HTH
> DaveA
> 
> 

Recalling (from a brief foray into college Chem.) that a result could not be 
displayed with precision greater than the least precise component that bore 
[the result].  So, yes, I could accept my input as the arbitrator of accuracy.

A scenario:

Calculating the coordinates of a forward station from a given base station 
would require [perhaps] the bearing (an angle from north, say) and distance 
from hither to there.  Calculating the north coordinate would set up this 
relationship, e.g.:

cos(3° 22' 49.6") x 415.9207'(Hyp) = adjacent side(North)

My first requirement, and this is the struggle I (we) are now engaged in, is to 
convert my bearing angle (3° 22' 49.6") to decimal degrees, such that I can 
assign its' proper cosine value.  Now, I am multiplying these two very refined 
values (yes, the distance really is honed down to 10,000'ths of a foot-that's 
normal in surveying data); within the bowels of the computer's blackboard 
scratch-pad, I cannot allow errors to evolve and emerge.

Were I to accumulate many of these "legs" into perhaps a 15 mile 
traverse-accumulating little computer errors along the way-the end result could 
be catastrophically wrong.

(Recall that in the great India Survey in the 1800's, Waugh got the elevation 
of Mt. Everest wrong by almost 30' feet for just this exact same reason.)  In 
surveying, we have a saying, "Measure with a micrometer, mark with chalk, cut 
with an axe".  Accuracy [in math] is a sacred tenet.

So, I am setting my self very high standards of accuracy, simply because those 
are the standards imposed by the project I am adapting, and I can require 
nothing less of my finished project.


  

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread Dave Angel



Lowell Tackett wrote:

--- On Tue, 4/20/10, Steven D'Aprano  wrote:

  

From: Steven D'Aprano 




The simplest, roughest way to fix these sorts of problems
(at the risk 
of creating *other* problems!) is to hit them with a

hammer:



round(18.15*100) == 1815
  

True



Interestingly, this is the [above] result when I tried entered the same snippet:

Python 2.5.1 (r251:54863, Oct 14 2007, 12:51:35)
[GCC 3.4.1 (Mandrakelinux 10.1 3.4.1-4mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
  

round(18.15)*100 == 1815


False
  



But you typed it differently than Steven.  He had   round(18.15*100), 
and you used round(18.15)*100


Very different.   His point boils down to comparing integers, and when 
you have dubious values, round them to an integer before comparing.  I 
have my doubts, since in this case it would lead to bigger sloppiness 
than necessary.


round(18.154 *100) == 1815

probably isn't what you'd want.

So let me ask again, are all angles a whole number of seconds?  Or can 
you make some assumption about how accurate they need to be when first 
input (like tenths of a second, or whatever)?  If so use an integer as 
follows:


val =  rounddegrees*60)+minutes)*60) + seconds)*10)

The 10 above is assuming that tenths of a second are your quantization.

HTH
DaveA

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-21 Thread spir ☣
On Tue, 20 Apr 2010 19:11:24 -0700 (PDT)
Lowell Tackett  wrote:

> > >>> round(18.15*100) == 1815  
> > True  
> 
> Interestingly, this is the [above] result when I tried entered the same 
> snippet:
> 
> Python 2.5.1 (r251:54863, Oct 14 2007, 12:51:35)
> [GCC 3.4.1 (Mandrakelinux 10.1 3.4.1-4mdk)] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
> >>> round(18.15)*100 == 1815  
> False
> >>>  
> 
> But...I'm just offering that for its' curiosity value, not to contradict your 
> comments or the case you are making.

hum hum hum...

Denis


vit esse estrany ☣

spir.wikidot.com
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread Lowell Tackett

>From the virtual desk of Lowell Tackett  



--- On Tue, 4/20/10, Steven D'Aprano  wrote:

> From: Steven D'Aprano 
> Subject: Re: [Tutor] the binary math "wall"
> To: tutor@python.org
> Date: Tuesday, April 20, 2010, 7:39 PM
> On Wed, 21 Apr 2010 02:58:06 am
> Lowell Tackett wrote:
> > I'm running headlong into the dilemma of binary math
> representation, 
> with game-ending consequences, e.g.:
> > >>> 0.15
> >
> > 0.14999
> >
> > Obviously, any attempts to manipulate this value,
> under the misguided
> > assumption that it is truly "0.15" are ill-advised,
> with inevitable
> > bad results.
> 
> That really depends on what sort of manipulation you are
> doing.
> 
> >>> x = 0.15
> >>> x
> 0.14999
> >>> x*100 == 15
> True
> 
> Seems pretty accurate to me.
> 
> However:
> 
> >>> 18.15*100 == 1815
> False
> 
> 
> The simplest, roughest way to fix these sorts of problems
> (at the risk 
> of creating *other* problems!) is to hit them with a
> hammer:
> 
> >>> round(18.15*100) == 1815
> True

Interestingly, this is the [above] result when I tried entered the same snippet:

Python 2.5.1 (r251:54863, Oct 14 2007, 12:51:35)
[GCC 3.4.1 (Mandrakelinux 10.1 3.4.1-4mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> round(18.15)*100 == 1815
False
>>>

But...I'm just offering that for its' curiosity value, not to contradict your 
comments or the case you are making.
> 
> [...]
> > What I'm shooting...is an algorithm
> that converts a
> > deg/min/sec formatted number to decimal degrees. 
> It [mostly] worked...which exposed the flaw.
> 
> I'm afraid that due to the nature of floating point, this
> is a hard 
> problem. Even the professionals at Hewlett-Packard's
> scientific 
> calculator division don't always get it right, and they are
> *extremely* 
> careful:
> 
> http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/archv018.cgi?read=132690
> 

Interesting that you raise the *hallowed* 48GX as a standard.  I have one (of 
the two I own) sitting next to me here, and have been using it as the bar 
against which to compare my computer.  Using the HMS+/-/-> etc. functions, I 
get pretty darned accurate results.  (Wish I'd known in time that HP was gonna 
throw the "48's" down the drain-I would own a lot more than two of them!)

> The best result I can suggest is, change the problem! Don't
> pass 
> degrees-minutes-seconds around using a floating point
> value, but as a 
> tuple with distinct (DEG, MIN, SEC) integer values. Or
> create a custom 
> class.
> 
> But if you really need D.MMSS floats, then something like
> this should be 
> a good start.:
> 
> def dms2deg(f):
> """Convert a floating point number formatted
> as D.MMSS 
> into degrees.
> """
> mmss, d = math.modf(f)
> assert d == int(f)
> if mmss >= 0.60:
> raise ValueError(
> 'bad fractional part, expected
> < .60 but got %f' % mmss)
> mmss *= 100
> m = round(mmss)
> if m >= 60:
> raise ValueError('bad minutes,
> expected < 60 but got %d' % m)
> s = round((mmss - m)*100, 8)
> if not 0 <= s < 60.0:
> raise ValueError('bad seconds,
> expected < 60.0 but got %f' % s)
> return d + m/60.0 + s/3600.0
> 
> 
> >>> dms2deg(18.15)
> 18.25
> >>> dms2deg(18.1515)
> 18.2541666
> 
> 
> which compares well to my HP-48GX:
> 
> 18.15 HMS->
> 
> gives 18.25, and:
> 
> 18.1515 HMS->
> 
> gives 18.254167.
> 
> 
> Note though that this still fails with some valid input. I
> will leave 
> fixing it as an exercise (or I might work on it later, time
> 
> permitting).
> 
> 
> -- 
> Steven D'Aprano
> ___
> Tutor maillist  -  Tutor@python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
> 

What you've provided with your comments is more of what I've received wholesale 
in this entire discourse--an incredible wealth of new insight and ways of 
looking at the problem.  Don't think you grasp how new I am at this, and how 
even what little I've tried to "pull off"-on my own-is way out at the edge of 
the "box" for me.  Someone wondered if performance was an issue that could 
effect my choice

Re: [Tutor] the binary math "wall"

2010-04-20 Thread Steven D'Aprano
On Wed, 21 Apr 2010 02:58:06 am Lowell Tackett wrote:
> I'm running headlong into the dilemma of binary math representation, 
with game-ending consequences, e.g.:
> >>> 0.15
>
> 0.14999
>
> Obviously, any attempts to manipulate this value, under the misguided
> assumption that it is truly "0.15" are ill-advised, with inevitable
> bad results.

That really depends on what sort of manipulation you are doing.

>>> x = 0.15
>>> x
0.14999
>>> x*100 == 15
True

Seems pretty accurate to me.

However:

>>> 18.15*100 == 1815
False


The simplest, roughest way to fix these sorts of problems (at the risk 
of creating *other* problems!) is to hit them with a hammer:

>>> round(18.15*100) == 1815
True

[...]
> What I'm shooting for, by the way, is an algorithm that converts a
> deg/min/sec formatted number to decimal degrees.  It [mostly] worked,
> until I stumbled upon the peculiar cases of 15 minutes and/or 45
> minutes, which exposed the flaw.

I'm afraid that due to the nature of floating point, this is a hard 
problem. Even the professionals at Hewlett-Packard's scientific 
calculator division don't always get it right, and they are *extremely* 
careful:

http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/archv018.cgi?read=132690

The best result I can suggest is, change the problem! Don't pass 
degrees-minutes-seconds around using a floating point value, but as a 
tuple with distinct (DEG, MIN, SEC) integer values. Or create a custom 
class.

But if you really need D.MMSS floats, then something like this should be 
a good start.:

def dms2deg(f):
"""Convert a floating point number formatted as D.MMSS 
into degrees.
"""
mmss, d = math.modf(f)
assert d == int(f)
if mmss >= 0.60:
raise ValueError(
'bad fractional part, expected < .60 but got %f' % mmss)
mmss *= 100
m = round(mmss)
if m >= 60:
raise ValueError('bad minutes, expected < 60 but got %d' % m)
s = round((mmss - m)*100, 8)
if not 0 <= s < 60.0:
raise ValueError('bad seconds, expected < 60.0 but got %f' % s)
return d + m/60.0 + s/3600.0


>>> dms2deg(18.15)
18.25
>>> dms2deg(18.1515)
18.2541666


which compares well to my HP-48GX:

18.15 HMS->

gives 18.25, and:

18.1515 HMS->

gives 18.254167.


Note though that this still fails with some valid input. I will leave 
fixing it as an exercise (or I might work on it later, time 
permitting).


-- 
Steven D'Aprano
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread spir ☣
On Tue, 20 Apr 2010 14:45:50 -0400
Dave Angel  wrote:

> If all values are made up of  degrees/minutes/seconds, and seconds is a 
> whole number, then store values as num-seconds, and do all arithmetic on 
> those values.  Only convert them back to deg/min/sec upon output.

This seems the most direct answer of the issue. If performance is not critical, 
I would even write a small Angle type with ° ' '' int attributes to get rid of 
(read: abstract away) all complexity once and for all.

Denis


vit esse estrany ☣

spir.wikidot.com
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread Dave Angel

Lowell Tackett wrote:

I'm running headlong into the dilemma of binary math representation, with 
game-ending consequences, e.g.:

  

0.15


0.14999

Obviously, any attempts to manipulate this value, under the misguided assumption that it 
is truly "0.15" are ill-advised, with inevitable bad results.

the particular problem I'm attempting to corral is thus:

  

math.modf(18.15)


(0.14858, 18.0)

with some intermediate scrunching, the above snippet morphs to:

  

(math.modf(math.modf(18.15)[0]*100)[0])/.6


1.4298

The last line should be zero, and needs to be for me to continue this algorithm.

Any of Python's help-aids that I apply to sort things out, such as formatting (%), or modules like 
"decimal" do nothing more than "powder up" the display for visual consumption (turning it 
into a string).  The underlying float value remains "corrupted", and any attempt to continue with 
the math adapts and re-incorporates the corruption.

What I'm shooting for, by the way, is an algorithm that converts a deg/min/sec 
formatted number to decimal degrees.  It [mostly] worked, until I stumbled upon 
the peculiar cases of 15 minutes and/or 45 minutes, which exposed the flaw.

What to do?  I dunno.  I'm throwing up my hands, and appealing to the "Council".

(As an [unconnected] aside, I have submitted this query as best I know how, using plain text and 
the "tu...@..." address.  There is something that either I, or my yahoo.com mailer *or 
both* doesn't quite "get" about these mailings.  But, I simply do my best, following 
advice I've been offered via this forum.  Hope this --mostly-- works.)

>From the virtual desk of Lowell Tackett  



  
One of the cases you mention is 1.666The decimal package won't 
help that at all.  What the decimal package does for you is two-fold:

   1) it means that what displays is exactly what's there
   2) it means that errors happen in the same places where someone 
doing it "by hand" will encounter.


But if you literally have to support arbitrary rational values 
(denominators other than 2 or 5), you would need to do fractions, either 
by explicitly keeping sets of ints, or by using a fractions library.  
And if you have to support arbitrary arithmetic, there's no answer other 
than hard analysis.


This is not a Python-specific problem.  Floating point has had such 
issues in every language I've dealt with since 1967, when I first 
learned Fortran.  If you compare two values, the simplest mechanism is

   abs(a-b) < delta

where you have to be clever about what small value to use for delta.

If all values are made up of  degrees/minutes/seconds, and seconds is a 
whole number, then store values as num-seconds, and do all arithmetic on 
those values.  Only convert them back to deg/min/sec upon output.


DaveA

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread Lowell Tackett

>From the virtual desk of Lowell Tackett  



--- On Tue, 4/20/10, Luke Paireepinart  wrote:

> From: Luke Paireepinart 
> Subject: Re: [Tutor] the binary math "wall"
> To: "Lowell Tackett" 
> Cc: "tutor" 
> Date: Tuesday, April 20, 2010, 1:20 PM
> On Tue, Apr 20, 2010 at 11:58 AM,
> Lowell Tackett
> 
> wrote:
> > I'm running headlong into the dilemma of binary math
> representation, with game-ending consequences, e.g.:
> >
> >>>> 0.15
> > 0.14999
> >
> 
> Yes, floats are slightly inaccurate.
> 
> But I think your problem is that your math is wrong.
> You are assuming...
> If your equations cannot handle this, then coerce the value
> to 1.
> if .999 < i < 1.1:
> i = 1
> 
> And before you say "but that is just a hack", no, that is
> the nature...
> But you really just need to adapt...
> 
> May I suggest another approach though?
> 
> Consider this:
> >>> a = 18.15
> >>> a
> 18.149
> >>> a = '18.15'
> >>> degree, min = map(int, a.split('.'))
> >>> degree
> 18
> >>> min
> 15
> 
> Supposing you get your input as a string.
> Basically the second you let your value end up stored as a
> float,
> there's no turning back...
> 
> Eventually you will develop a distrust for floats...
> 
> Hope that helps,
> -Luke
> 

I was gonna go out jogging - and in a coupla hours check to see if anyone had 
tried to take this "on"; going out the door I decided to take a quick look.  
Ahem...

These responses just "blow me away" on a couple of levels.  I'm choosing 
"Luke"'s offering as representative.  Within  some great folks had 
read, parsed, and re-structured my query.  My narrow focus yells out my 
inexperience...I was trying as hard as I could, with limited tools, to solve 
the issue.  That's fine.  But...the breadth and depth of the responses 
represent nothing short of a paradigm shift in my window into this world of 
"hacking".

Ya'll have insights of a scale unimagined in the confines of my "thinking box". 
 (Now, I gotta go out and jog just to clear my head!)  Then come back...and 
pull the blinds closed...and absorb; and come up for air in maybe a week or so. 
 And only then, be able to offer my thanks with an objective sense of how much 
I've been helped today...Wow!


  
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread Lie Ryan
On 04/21/10 02:58, Lowell Tackett wrote:
> I'm running headlong into the dilemma of binary math representation, with 
> game-ending consequences, e.g.:
> 

Never use float for representing numbers, use float to represent a
"magnitude", do not rely on the exact representation of the number itself.

If you need to control the representation of your number, either keep
the number as integers or string or use fixed-point arithmetic
(Decimal), depending on your use case.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread spir ☣
On Tue, 20 Apr 2010 09:58:06 -0700 (PDT)
Lowell Tackett  wrote:

> I'm running headlong into the dilemma of binary math representation, with 
> game-ending consequences, e.g.:
> 
> >>> 0.15
> 0.14999
> [...]
> The last line should be zero, and needs to be for me to continue this 
> algorithm.
> 
> Any of Python's help-aids that I apply to sort things out, such as formatting 
> (%), or modules like "decimal" do nothing more than "powder up" the display 
> for visual consumption (turning it into a string).  The underlying float 
> value remains "corrupted",

You are wrong:

>>> from decimal import Decimal
>>> s  = "0.15"
>>> Decimal(s) == float(s)

This shows, maybe weirdly, that the decimal version != 0.14999 
--since it is actually equal to 0.15. Decimals are *not* internally represented 
as binary values, but instead with groups of bits each coding a *decimal* 
digit; this is precisely the point. Else why do you think developpers would 
cope with such a problem?


Denis


vit esse estrany ☣

spir.wikidot.com
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread Wayne Werner
On Tue, Apr 20, 2010 at 11:58 AM, Lowell Tackett wrote:

> I'm running headlong into the dilemma of binary math representation, with
> game-ending consequences, e.g.:
>
> >>> 0.15
> 0.14999
>
> Obviously, any attempts to manipulate this value, under the misguided
> assumption that it is truly "0.15" are ill-advised, with inevitable bad
> results.
>
> the particular problem I'm attempting to corral is thus:
>
> >>> math.modf(18.15)
> (0.14858, 18.0)
>
> with some intermediate scrunching, the above snippet morphs to:
>
> >>> (math.modf(math.modf(18.15)[0]*100)[0])/.6
> 1.4298
>
> The last line should be zero, and needs to be for me to continue this
> algorithm.
>
> Any of Python's help-aids that I apply to sort things out, such as
> formatting (%), or modules like "decimal" do nothing more than "powder up"
> the display for visual consumption (turning it into a string).  The
> underlying float value remains "corrupted", and any attempt to continue with
> the math adapts and re-incorporates the corruption.
>

That is not precisely correct - modf first converts decimal to a float and
then applies the calculation. Try this instead:

def modf(mydecimal):
num = decimal.Decimal('1.0')
return (mydecimal%num, mydecimal//num)

On my machine this returns (with
In [18]: modf(d)
Out[18]: (Decimal('0.15'), Decimal('18'))

Which are easily converted.
In [30]: (modf(modf(d)[0]*100)[0])/decimal.Decimal('.6')
Out[30]: Decimal('0.0')

So your problem with decimal isn't that it lacks the precision you're
seeking - you're simply converting it to a float /before/ performing the
calculations, which makes turning it into a decimal in the first place
pretty much useless.

HTH,
Wayne
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread Jerry Hill
On Tue, Apr 20, 2010 at 12:58 PM, Lowell Tackett
 wrote:
> Any of Python's help-aids that I apply to sort things out, such as formatting 
> (%), or modules like "decimal" do nothing more than "powder up" the display 
> for visual consumption (turning it into a string).  The underlying float 
> value remains "corrupted", and any attempt to continue with the math adapts 
> and re-incorporates the corruption.

Using the decimal module does not convert anything to strings.  The
decimal module gives you floating point arithmetic with base 10 rather
than base 2.

You examples seem to work okay for me using decimals:

IDLE 2.6.4
>>> import decimal
>>> n = decimal.Decimal("18.15")

>>> n
Decimal('18.15')

>>> print n
18.15

>>> divmod(n, 1)
(Decimal('18'), Decimal('0.15'))

>>> divmod(divmod(n, 1)[1]*100, 1)[1]/decimal.Decimal("0.6")
Decimal('0.0')

If you need to avoid floating point calculations entirely, you might
try the fractions module (new in python 2.6):

>>> import fractions
>>> n = fractions.Fraction("18.15")

>>> n
Fraction(363, 20)

>>> print n
363/20

>>> divmod(divmod(n, 1)[1]*100, 1)[1]/fractions.Fraction("0.6")
Fraction(0, 1)

>>> print divmod(divmod(n, 1)[1]*100, 1)[1]/fractions.Fraction("0.6")
0

and if you need to convert to float at the end:

>>> float(divmod(divmod(n, 1)[1]*100, 1)[1]/fractions.Fraction("0.6"))
0.0
>>>

-- 
Jerry
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] the binary math "wall"

2010-04-20 Thread Luke Paireepinart
On Tue, Apr 20, 2010 at 11:58 AM, Lowell Tackett
 wrote:
> I'm running headlong into the dilemma of binary math representation, with 
> game-ending consequences, e.g.:
>
 0.15
> 0.14999
>
> Obviously, any attempts to manipulate this value, under the misguided 
> assumption that it is truly "0.15" are ill-advised, with inevitable bad 
> results.
>

Yes, floats are slightly inaccurate.
No, this usually doesn't cause problems.

You can use the decimal module if you want.
But I think your problem is that your math is wrong.
You are assuming that your float values are precise and they are not.
You must check ranges when dealing with float values, not for specific values.
I.E. you should never depend on a value being 1 in a float calculation,
instead your equations need to be robust enough to deal with values
very close to 1 as well.
If your equations cannot handle this, then coerce the value to 1.
if .999 < i < 1.1:
i = 1

And before you say "but that is just a hack", no, that is the nature
of floating-point values.  No one ever claimed that they were precise
or that you should depend on their values being precise.

If you really care so much, use the decimal module.
But you really just need to adapt your formulas from the ideal to the
reality, in which the values are not necessarily complete.

May I suggest another approach though?
Why even process these values as floats?

Consider this:
>>> a = 18.15
>>> a
18.149
>>> a = '18.15'
>>> degree, min = map(int, a.split('.'))
>>> degree
18
>>> min
15

Supposing you get your input as a string.
Basically the second you let your value end up stored as a float,
there's no turning back.  You need to get ahold of this value before
it becomes a float and deal with it in a different way.  The most
straightforward is to deal with the parts individually as integers.

Eventually you will develop a distrust for floats and you will
intrinsically know where and when you should / shouldn't use them ;)

Hope that helps,
-Luke
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] the binary math "wall"

2010-04-20 Thread Lowell Tackett
I'm running headlong into the dilemma of binary math representation, with 
game-ending consequences, e.g.:

>>> 0.15
0.14999

Obviously, any attempts to manipulate this value, under the misguided 
assumption that it is truly "0.15" are ill-advised, with inevitable bad results.

the particular problem I'm attempting to corral is thus:

>>> math.modf(18.15)
(0.14858, 18.0)

with some intermediate scrunching, the above snippet morphs to:

>>> (math.modf(math.modf(18.15)[0]*100)[0])/.6
1.4298

The last line should be zero, and needs to be for me to continue this algorithm.

Any of Python's help-aids that I apply to sort things out, such as formatting 
(%), or modules like "decimal" do nothing more than "powder up" the display for 
visual consumption (turning it into a string).  The underlying float value 
remains "corrupted", and any attempt to continue with the math adapts and 
re-incorporates the corruption.

What I'm shooting for, by the way, is an algorithm that converts a deg/min/sec 
formatted number to decimal degrees.  It [mostly] worked, until I stumbled upon 
the peculiar cases of 15 minutes and/or 45 minutes, which exposed the flaw.

What to do?  I dunno.  I'm throwing up my hands, and appealing to the "Council".

(As an [unconnected] aside, I have submitted this query as best I know how, 
using plain text and the "tu...@..." address.  There is something that either 
I, or my yahoo.com mailer *or both* doesn't quite "get" about these mailings.  
But, I simply do my best, following advice I've been offered via this forum.  
Hope this --mostly-- works.)

>From the virtual desk of Lowell Tackett  



  
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor