Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

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

by HollyKing (Pilgrim)
on Jun 29, 2007 at 18:00 UTC ( #624129=perlquestion: print w/ replies, xml ) 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.

Comment on Is there a better way to call fe(get|set)round?
Select or Download Code
Re: Is there a better way to call fe(get|set)round?
by toolic (Chancellor) 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 }
    __________________________________________________________________________________

    ^M Free your mind!

      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.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://624129]
Approved by Corion
Front-paged by bart
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (13)
As of 2014-09-19 09:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (133 votes), past polls