No such thing as a small change PerlMonks

### Is there a better way to call fe(get|set)round?

by HollyKing (Pilgrim)
 on Jun 29, 2007 at 18:00 UTC Need Help??
HollyKing has asked for the wisdom of the Perl Monks concerning the following question:

Greetings!

I have a need to control the rounding direction being used for floating point calculations. In C I would just call fegetround() and fesetround(). I have used Inline::C with some success, but I wonder if there isn't a better way to accomplish the same thing.

Is there some magic flag or module that will let me manipulate the rounding mode? I think my options are:

1. Keep using Inline::C
2. Write a new module in C to expose the functions defined in fenv.h
3. ...

I've included a small program below that shows my current solution. This works with Strawberry Perl although I have yet to test it anywhere else so YMMV.

## Sample Code

```#!/usr/bin/perl
use warnings;
use strict;

use Inline C => <<'END_C';

#include <fenv.h>

int _getround()
{
return fegetround();
}

int _setround(int mode)
{
return fesetround(mode);
}

int _round_down()
{
return fesetround(FE_DOWNWARD);
}

END_C

## simulate my object
my \$one   = 1.0;
my \$three = 3.0;

## save the rounding mode and set to round towards negative infinity
my \$mode = _getround();
my \$changed = _round_down();

## perform the calculations
my \$lb = \$one / \$three;
my \$ub = -( -\$one / \$three );

## restore the original rounding mode to be nice
_setround(\$mode);

## display the results
printf( "\\$lb = %.23f\n", \$lb );
printf( "\\$ub = %.23f\n", \$ub );
print "\\$lb == \\$ub ", \$lb == \$ub ? 'true' : 'false', "\n";
print "\\$changed = \$changed\n";

## Sample Output

```P:\>fround
\$mode = 0
\$lb = 0.33333333333333331000000
\$ub = 0.33333333333333337000000
\$lb == \$ub false
\$changed = 0

Owl looked at him, and wondered whether to push him off the tree; but, feeling that he could always do it afterwards, he tried once more to find out what they were talking about.

Replies are listed 'Best First'.
Re: Is there a better way to call fe(get|set)round?
by toolic (Bishop) on Jun 30, 2007 at 02:20 UTC
I just happened to be browsing CPAN, and I stumbled across the Number::WithError module, which is described as "Numbers with error propagation and rounding".

I honestly do not know if this will help you because I have never used this module, but it sounds promising. There are rounding and numeric comparison methods.

Good luck.

Thanks! I have looked at Number::WithError and while a nice module it doesn't answer my question.

Owl looked at him, and wondered whether to push him off the tree; but, feeling that he could always do it afterwards, he tried once more to find out what they were talking about.

Re: Is there a better way to call fe(get|set)round?
by bart (Canon) on Jun 30, 2007 at 22:28 UTC
I recently read something about custom pragmas being allowed in experimental and future releases of Perl. So, I'm thinking that for the user, it might be a good idea if you make it a pragma. That way, its scope will be lexical, and outside the embedding block, floating rounding will happen as usual. Well, that's my basic idea, anyway; I'm not sure you can successfully use pragmas for this purpose. integer is a pragma, and my role model here.

Another idea is using a global tied variable (setting a value will call fesetround() and reading it fegetround()), so you can use local on it. Hence, the scope will then be temporal instead of lexical, so calculations in other modules will be affected while called from the current scope. And when you leave the block, the old value will be restored.

Thanks for the ideas. I'll keep them in mind should I end up implementing this.

Owl looked at him, and wondered whether to push him off the tree; but, feeling that he could always do it afterwards, he tried once more to find out what they were talking about.

Re: Is there a better way to call fe(get|set)round?
by Moron (Curate) on Jul 02, 2007 at 12:52 UTC
Something like ...
```package Somename;
use Math::BigFloat;

sub new {
my \$class = shift;
my \$self = bless {};
\$self -> { underlying } = Math::BigFloat -> new( @_ );
return ( \$self, \$class );
}

sub fsetround { # e.g. \$obj -> fsetround( mode => 'FE_DOWNWARD' );
my \$self = shift;
my %opt = @_;
while ( my ( \$k, \$v ) = each %opt ) {
\$self -> { \$k } = \$v;
}

# set defaults here e.g. for round by default
# to 17 digits from the left
\$self -> { scale } ||= 17;

}

sub fgetround
my \$self = shift;

if ( \$self -> { mode } eq 'FE_DOWNWARD' ) {
my \$bf = \$self -> { underlying };
return \$bf -> ffround( -( \$self -> { scale } ) );
}
# elsif ...
# etc. for the other features of fenv
}
__________________________________________________________________________________

You missed the point again. The rounding mode being queried or altered by the OP, is that of the math coprocessor and is applied to the results of all FP operations done by it. The 4 modes are as defined by the IEEE Floating Point standard. The two calls, fe(get|set)round are C/C++ compiler provided functions to get/set that hardware rounding mode.

Moving to using software emulated, infinite precision FP to achieve the same end would for most applications be a disaster. With Math::BigFloat, FP calculations run anything from a few hundred to a few 10s of thousands times more slowly depending upon the configuration and underlying libraries used. Okay if your calculating the final cost of a few dozen items in an IO bound shopiing cart application, but for any kind of serious math, way too slow.

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
Yes, exactly. Thanks!

Owl looked at him, and wondered whether to push him off the tree; but, feeling that he could always do it afterwards, he tried once more to find out what they were talking about.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://624129]
Approved by Corion
Front-paged by bart
help
Chatterbox?
 [ovedpo15]: can't I use just use lib \$FindBin::Bin/../ bin" asuming that p2 is in ./bin and p1 is in /config? it says "cant find p2.pm" altought p2 is p2.pl [moritz]: ovedpo15 "use lib" is only for .pm files [moritz]: if you don't have .pm file, you might to use "require" or "do" with an absolute path [ovedpo15]: I need to use FindBin thought. does FindBin finds only modules? or it can find perl script also? [moritz]: maybe you should start looking at the documentation of FindBin?

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (6)
As of 2018-03-17 20:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
When I think of a mole I think of:

Results (226 votes). Check out past polls.

Notices?