How to remove a user from my friend list?
Dealing with floats and rounding
Hello Guest
  
  • Login
• Register…
• Start blog
  • Who, Where, When
• What can I do?
• What to Read?
  • Polls
• Avatars
• Interests
  • Cities and Countries
• Random blog
• Users search
  • Search
• Games
• Tests
• QAIX
  • Сообщества
• Talxy Chat
• Horoscope
• Online
 
Зарегистрируйся!

QAIX > Perl web-programming > Dealing with floats and rounding 10 October 2008 10:44:19

  Recent blog posts: 
  They have birthday today: 
  Forums:   
  Discuss: 
  Recent forum topics: 
  Recent forum comments:
  Moderators:

Dealing with floats and rounding

Douglas Wilson 10 October 2008 10:44:19
 I know dealing with float columns are fraught with rounding errors, but I'm
just wondering about the best way to deal with them.

I'm using DBD::Sybase, and some of our floats have the smallest
possible value... -1.7976931348623157­e+308

When I just do:

select float_column from my_table

into a perl variable, and use it to insert into another table,
I get an error because the value gets rounded to:
-1.79769313486232e+­308
which is too small to fit in a float column.

So, either I can:
select convert(varchar, float_column) from my_table

or instead, after selecting, I can use sprintf:
$float_column = sprintf("%1.16e", $float_column);

The first solution is okay if I know in advance which columns are floats,
while the second solution seems better if I need to dynamically deal
with unknown column types (e.g., "select *").

Does anyone have any better (or just other) ideas?

A DBI or DBD "select float as string" sort of flag would be nice that
would automatically do the conversion...is that
a good idea, or would it be feasible?

Thanks,
Doug

Add comment
Mr. Shawn H. Corey 7 October 2008 20:32:52 permanent link ]
 On Tue, 2008-10-07 at 09:02 -0700, Douglas Wilson wrote:
or instead, after selecting, I can use sprintf:
$float_column = sprintf("%1.16e", $float_column);
The first solution is okay if I know in advance which columns are
floats,
while the second solution seems better if I need to dynamically deal
with unknown column types (e.g., "select *").
Does anyone have any better (or just other) ideas?

sprintf is the preferred way of rounding off floats in Perl. There is a
whole branch of mathematics, numerical analysis, which deals with
problems like this, so don't expect things to be easy.

BTW, don't use "SELECT *". If your DBA rebuilds the tables with a
different column order, your code will fail. Specifically name the
columns (or if you really have to, use the _hashref methods to fetch;
that way you can select the correct column via the hash).


--
Just my 0.00000002 million dollars worth,
Shawn

Linux is obsolete.
-- Andrew Tanenbaum


Add comment
Derek Jones 7 October 2008 20:58:44 permanent link ]
 use Math::Round;

All of the common languages suffer from rounding problems inherent in
IEEE rounding (round-to-even and other issues). Math::Round resolves
these issues.

$a=4712.5;

$b=round $a;

printf "%s %5.0f %5.0f\n", $a, $a, $b;


I hit this while comparing SAS output (which does do proper (within
machine limits) "mathematical" rounding that we all learned about in
school. The C libraries from which Perl and other C-lib derived
languages take their rounding functions are the cause of some potential
grief here and comparison with 4 other languages vs. SAS showed SAS
getting it right each time. Using Math::Round - so did Perl. We're
talking way down to DP as well.

This caused the group I work with some issues as I was rewriting some
SAS code in Perl and our regression tests were not matching - and we
were talking adding up millions of rows of data with N DP to be
concerned about. Math::Round fixed that.

Kind regards

Derek Jones


Mr. Shawn H. Corey wrote:
On Tue, 2008-10-07 at 09:02 -0700, Douglas Wilson wrote:
or instead, after selecting, I can use sprintf:
$float_column = sprintf("%1.16e", $float_column);
The first solution is okay if I know in advance which columns are
floats,
while the second solution seems better if I need to dynamically deal
with unknown column types (e.g., "select *").
Does anyone have any better (or just other) ideas?
sprintf is the preferred way of rounding off floats in Perl. There is a
whole branch of mathematics, numerical analysis, which deals with
problems like this, so don't expect things to be easy.
BTW, don't use "SELECT *". If your DBA rebuilds the tables with a
different column order, your code will fail. Specifically name the
columns (or if you really have to, use the _hashref methods to fetch;
that way you can select the correct column via the hash).


Add comment
Douglas Wilson 7 October 2008 21:43:52 permanent link ]
 On Tue, Oct 7, 2008 at 9:32 AM, Mr. Shawn H. Corey <shawnhcorey@magma.­ca> wrote:
On Tue, 2008-10-07 at 09:02 -0700, Douglas Wilson wrote:
BTW, don't use "SELECT *". If your DBA rebuilds the tables with a
different column order, your code will fail. Specifically name the
columns (or if you really have to, use the _hashref methods to fetch;
that way you can select the correct column via the hash).

Don't worry, I only use select * when I don't care about order, and I
usually use bind_columns..e.g.:­

my $sth = $dbh->prepare("sele­ct * from my_table");
$sth->execute();
my @names = @{$sth->{NAME_lc}};­
my %row; $sth->bind_columns(­\@row{@names});
while ( $sth->fetch() ) {
...
}

Cheers,
Doug

Add comment
Dr.Ruud 10 October 2008 10:44:19 permanent link ]
 Derek Jones schreef:

All of the common languages suffer from rounding problems inherent in
IEEE rounding (round-to-even and other issues). Math::Round resolves
these issues.

If you don't round to even (and your numbers are of the same sign), then
the totals of the original values and the total of the rounded values
will be more different.
That is why round-to-even is also called "bankers rounding", for details
see http://en.wikipedia­.org/wiki/Rounding


$a=4712.5;
$b=round $a;
printf "%s %5.0f %5.0f\n", $a, $a, $b;
I hit this while comparing SAS output (which does do proper (within
machine limits) "mathematical" rounding that we all learned about in
school. The C libraries from which Perl and other C-lib derived
languages take their rounding functions are the cause of some
potential grief here and comparison with 4 other languages vs. SAS
showed SAS getting it right each time. Using Math::Round - so did
Perl. We're talking way down to DP as well.
This caused the group I work with some issues as I was rewriting some
SAS code in Perl and our regression tests were not matching - and we
were talking adding up millions of rows of data with N DP to be
concerned about. Math::Round fixed that.

Are you sure that your regression tests were "right"?
:)­

--
Affijn, Ruud

"Gewoon is een tijger."


Add comment
 

Add new comment

As:
Login:  Password:  
 
 
  
 
Пожалуйста, относитесь к собеседникам уважительно, не используйте нецензурные слова, не злоупотребляйте заглавными буквами, не публикуйте рекламу и объявления о купле/продаже, а также материалы нарушающие сетевой этикет или УК РФ.


QAIX > Perl web-programming > Dealing with floats and rounding 10 October 2008 10:44:19

see also:
NOMINATION: Fly Cooter for Darth Bawl…
SPAN with DIV features
Help with my new web site?
пройди тесты:
see also:
Samsung CLP-300 Color Laser Printer
hp compatible toner cartridge Q2612A
Which color OPC drum we will use?

  Copyright © 2001—2008 QAIX
Idea: Miсhael Monashev
Помощь и задать вопросы можно в сообществе support.qaix.com.
Сообщения об ошибках оставляем в сообществе bugs.qaix.com.
Предложения и комментарии пишем в сообществе suggest.qaix.com.
Информация для родителей.
Write us at:
If you would like to report an abuse of our service, such as a spam message, please .