Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Re^2: Calculating base difference of numbers

by Anonymous Monk
on May 30, 2008 at 19:53 UTC ( #689327=note: print w/ replies, xml ) Need Help??


in reply to Re: Calculating base difference of numbers
in thread Calculating base difference of numbers

printf in the instance you have shown doesn't give me anything I can work with
I should have mentioned that the rates are comming in live 24/7 and I want to look at the base point movement as the rates change.
In the examples above I'm looking to see the base point movements of +1,+4 and -5.
Whatever solution I have to get this number must be simple enough that I can use in a function where any number with any number of decimal places is looked at and the difference to last known rate instance is calculated.


Comment on Re^2: Calculating base difference of numbers
Re^3: Calculating base difference of numbers
by friedo (Prior) on May 30, 2008 at 20:05 UTC

    I don't understand why you can't simply use subtraction, regardless of the decimal truncation in either of the operands.

    You're going to end up with some floating-point drift anyway; perhaps it would be a good idea to drop the decimal points and treat everything as integers, then divide by 10n when it's time to display the number to the user. (This is the recommended way of doing currency calculations so floating point error doesn't mess with your cents.)

Re^3: Calculating base difference of numbers
by almut (Canon) on May 30, 2008 at 20:20 UTC
    In the examples above I'm looking to see the base point movements of +1,+4 and -5.

    I'm not really sure I understand, but maybe something like this?

    #!/usr/bin/perl use strict; use warnings; print base_point_movement($_),"\n" for ( 1.5553 - 1.5552, 0.9984 - 0.998, 100.25 - 100.3, ); sub base_point_movement { my $diff = shift; (sprintf "%+e", $diff) =~ /([+-]\d)\./; return $1; }

    Output:

    +1 +4 -5

    Update: as has been pointed out, this only works for +/-9 — which is not too surprising, as it just extracts the before-comma digit of the difference in exponential floating-point representation  (not knowing what a "base point" is defined as, I figured it might suffice...).

    Anyhow, here's another variant, kind of extending the idea to what might have been meant — though honestly, I don't have the foggiest whether that's what the OP had in mind.  (Of course, this will also run into problems when the number of significant digits exceeds floating-point precision.)

    sub base_point_movement { my $bpm = sprintf "%+e", shift; $bpm =~ s/0*e.*$//; $bpm =~ tr/.//d; return $bpm; } print base_point_movement($_),"\n" for ( 1.5553 - 1.5552, # +1 1.5553 - 1.55, # +53 1.56 - 1.55, # +1 155.53 - 155.52, # +1 15553 - 15552, # +1 1555300 - 1555200, # +1 1555300 - 155520, # +139978 1555.300 - 1555.20, # +1 1555300 - 1555201, # +99 1.5553 - 1.555201, # +99 1.5553 - 1.55521, # +9 1.5553 - 1.555301, # -1 1.5553 - 1.55530101, # -101 1.5553 - 1.5553101, # -101 15553 - 15552.9999, # +1 15553.001 - 15552.999, # +2 15553.001 - 15552.9999, # +11 15553.1 - 15552.99, # +11 # etc. (you get the idea :) );
      That's it almut!

      Thanks....I looked at sprintf but couldn't figure it out....still much Perl goodness to learn from these monks!

      This fails when the difference is 10 or more base points. Try it with test data of 1.5563 - 1.5552

      Unless I state otherwise, all my code runs with strict and warnings

      Sadly this will fail for any movement of greater than 9 points. This problem is insoluble without a definition of what constitutes a point. Consider the upper number pair and some possible variations that could exist with trailing zero truncation:

      1.5553 - 1.5552 # 1 point 1.5553 - 1.55 # 53 points (your sub will fail with this) 1.56 - 1.55 # 1 point? 100 points? (insoluble from data alone)

      You either have to decide what is a point, or guess and accept that there will be errors:

      sub points { my ($was,$is,$exp) = @_; unless ($exp) { $was =~ m/\.(\d+)$/; my $x = $1 ? length($1) : 0; $is =~ m/\.(\d+)$/; my $y = $1 ? length($1) : 0; $exp = $x > $y ? $x : $y; } print "($exp) $was => $is\t"; $exp = 10**$exp; my $dif = $is*$exp - $was*$exp; # add correction factor to allow int to round correctly # also ensures that FP "error" such as 4.999999 ends up as +5 $dif += $dif < 0 ? -0.5 : +0.5; return sprintf "%+d", $dif; } print points(1.5553,1.5552), $/; print points(1.55,1.5553 ), $/; print points(1.55,1.56), $/; print points(1.55,1.56,4), $/; print points(0.9984,0.998), $/; __DATA__ (4) 1.5553 => 1.5552 -1 (4) 1.55 => 1.5553 +53 (2) 1.55 => 1.56 +1 (4) 1.55 => 1.56 +100 (4) 0.9984 => 0.998 -4

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://689327]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (5)
As of 2014-07-13 21:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (252 votes), past polls