Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: Calculating base difference of numbers

by toolic (Bishop)
on May 30, 2008 at 19:44 UTC ( [id://689324]=note: print w/replies, xml ) Need Help??


in reply to Calculating base difference of numbers

printf can be used to format numbers to a specified number of decimal places. For example, this will give you 5 decimal places:
printf "%.5f\n", (1.5553 - 1.5552); printf "%.5f\n", (0.9984 - 0.998); printf "%.5f\n", (100.25 - 100.3);

prints:

0.00010 0.00040 -0.05000

Replies are listed 'Best First'.
Re^2: Calculating base difference of numbers
by Anonymous Monk on May 30, 2008 at 19:53 UTC
    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.
      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 :) );

        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
        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
        That's it almut!

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

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

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (3)
As of 2024-04-24 02:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found