Pathologically Eclectic Rubbish Lister PerlMonks

### Re^2: Calculating base difference of numbers

 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

Replies are listed 'Best First'.
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 :)
);

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!

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

Create A New User
Domain Nodelet?
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 contemplating the Monastery: (7)
As of 2022-12-02 16:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My favourite new Perl feature (in 2022) ...

Results (43 votes). Check out past polls.

Notices?