user17241
user17241

Reputation: 317

How do I convert scientific to decimal notation?

I have a question concerning converting $calc value from scientific notation to decimal. Any idea please?

my $calc = log2($prob/$probWords);

push @result, join(' ',@words) ." (".$calc.")\n";

if(scalar(@result) == $bloc)
{
  $cmp += $bloc;
  print "$cmp lignes traités\n";
  writeToResultFile($outFile,@result);
  @result = ();
}

Upvotes: 1

Views: 4016

Answers (3)

Joel Berger
Joel Berger

Reputation: 20280

Alois Mahdal is on the right track, but having a hard time working out the kinks. Here is a different take on the matter. We can use Devel::Peek to see what Perl sees in the variable. Perl has three basic (non-reference) storage types, related to C types: strings are pointers (PV) and numbers can be either floats (NV, number value) or integers (IV).

#!/usr/bin/env perl

use strict;
use warnings;

use Devel::Peek; # Dump

my $x = "1e10";
Dump $x;

outputs

SV = PV(0x1204090) at 0x1225b80
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x1212ac0 "1e10"\0
  CUR = 4
  LEN = 16

PV is a string. You can see the value. Now it we coerce to a number, say by adding zero.

...
$x += 0;
Dump $x;

yielding

SV = PVNV(0xf018f0) at 0xf21b90
  REFCNT = 1
  FLAGS = (PADMY,IOK,pIOK)
  IV = 10000000000
  NV = 10000000000
  PV = 0xf0eac0 "1e10"\0
  CUR = 4
  LEN = 16

Now you can see that the variable hold both the original PV and the number value (NV) (as well as a integer value (IV)) representing 10 billion. The IOK tells us that it is considered an integer primarily at the moment. It keeps the other values in case you should want to coerce again.

So you see, coercion from a scientific value to a number is as easy as converting from a string to a number (adding zero is a common mechanism). To go the other way, use sprintf with a proper format.

N.B. For completeness, we can see the conversion to an NV by adding a decimal.

...
$x += 0.1;
Dump $x;

outputs

SV = PVNV(0x1ee0910) at 0x1f00b90
  REFCNT = 1
  FLAGS = (PADMY,NOK,pNOK)
  IV = 0
  NV = 10000000000.1
  PV = 0x1eedac0 "1e10"\0
  CUR = 4
  LEN = 16

and NOK tells Perl that it should now be a floating point value.

Upvotes: 2

Alois Mahdal
Alois Mahdal

Reputation: 11253

While Miguel's answer seems to be what you're looking for, I'll throw in some theory anyway: more formally correct answer would be: You can't. Luckily you don't need to anway.

Perl does not store notation with the variable. It should not even matter if it's a string or number: as long as number in any notation is stored in a string, it can be used as a number:

$a = "1e4";                             # $a now holds "1e4"
print $a . " (read 'one-e-four')\n";    # mentors on pronunciation
$a = $a / 1000;                         # $a now holds 10
$a = $a . "23";                         # $a now holds "1023" (or 1023 or even 1.023e3...)
$a = $a + 1;                            # $a now holds 1024 (or "1024")
print "Hello " . $a . " worlds\n";      # greets 1024 worlds

The conversion is implicit. In above example:

  1. Perl does not wonder what "1e4" would mean as a number until line 3, when it quickly reckons it as ten thousand, therefore yielding result ten, which in my example is assigned back to $a. Now the value stored is numeric.

  2. Now in string expression on the next line, ten is interpreted as "10" (decimal is the default notation for numeric values). Concatenation of these two strings yields string "1023".

  3. Same story as with the division: "1023" appears in numeric expression, therefore must be converted to number

Normally, however, you want to have more control about the conversion.

  • In case of conversion of [what came in as] string, to [what needs to be used as] number, one of typical reasons is that you are not 100% sure how the string form will look like: especially if it comes right from user, answer to "enter number" can be "100", but could be be also "0100", "hundred" or "your mother's age" (believe me, some users can be really nasty).

    That's what regular expressions (or probably other techniques) are for.

  • In the other case, if you want to use the value as part of a string, you might want to be sure how the number will look like--what notation or how many characters will be used.

    That's what sprintf and printf are for.

Since Perl is always ready to interpret any (numeric/string) value as number or string, you do not need to care about whether $a is internally numeric or string. On the other hand, what you still need to care about is the content of your variables.

Upvotes: 1

Miguel Prz
Miguel Prz

Reputation: 13792

you could use sprintf to convert your number to string and give it a concrete format. Example:

# Round number to 5 digits after decimal point
$calc_str = sprintf("%.5f", $calc);

Upvotes: 9

Related Questions