Convert Integer in to decimal Perl - perl

I need to convert the following integers numbers
29900
17940
1
in to decimal format like
299.00
179.40
0.01
I tried already Data/Types.pm but
to_decimal(1, 2)
return 1.00

Perl does not have data types in the sense of integer, float or string. All you need to do is divide by 100. If you want an output with two decimals, use sprintf to format it.
printf '%.02d', 29900 / 100;
Will output 299.00. Note that printf is like sprintf, but with printing instead of returning.
You can read perldata to learn more about what kinds of data Perl has.
Under the hood at the XS and C layer, there are of course data types. You can learn about them in perlguts. But the whole point of a higher language is to abstract those things away. So if all you do is write Perl code, you never need to care that those exist or how they work.

Related

sprintf : fixed point, big numbers and precision loss

I need to read some numbers in a database and write them into a text file using Perl.
In the table where are the numbers, the data format is defined as numeric (25,5) (it reads 25 digits, including 5 decimals).
I format the numbers in my file with a sprintf "%.5f", $myvalue to force 5 decimals and I just noticed that for greats values, there is a precision loss for numbers with more than 17 digits :
db = 123.12345
file = 123.12345 (OK)
db = 12345678901234891.12345
file = 12345678901234892.00000 (seems to be rounded to upper integer)
db = 12345678901234567890.12345
file = 12345678901234567000.00000 (truncation ?)
What is Perl's greatest precision for fixed decimal numbers?
I am aware of the concepts and limitations of floating point arithmetic in general, but I am not a Perl monk and I do not know the internals of Perl so I don't know if it is normal (or if it is related at all to floating point). I am not sure either if it is a internal limitation of Perl, or a problem related to the sprintf processing.
Is there a workaround or a dedicated module that could help with that problem?
Some notable points :
this is an additional feature of a system that already uses Perl, so using another tool is not an option
the data being crunched is financial so I need to keep every cent and I cannot cope with a +/- 10 000 units precision :^S
Once again, I am finding a solution right after asking SO. I am putting my solution here, to help a future visitor :
replace
$myout = sprintf "%.5f", $myvalue;
by
use Math::BigFloat;
$myout = Math::BigFloat->new($myvalue)->ffround( -5 )->bstr;
Without modules like Math::BigFloat, everything above 16 digits is pure magic... e.g.
perl -e 'printf "*10^%02d: %-.50g\n", $_, log(42)*(10**$_) for (0..20)'
produces
*10^00: 3.7376696182833684112267746968427672982215881347656
*10^01: 37.376696182833683224089327268302440643310546875
*10^02: 373.76696182833683224089327268302440643310546875
*10^03: 3737.6696182833684360957704484462738037109375
*10^04: 37376.6961828336861799471080303192138671875
*10^05: 373766.96182833681814372539520263671875
*10^06: 3737669.6182833681814372539520263671875
*10^07: 37376696.18283368647098541259765625
*10^08: 373766961.82833683490753173828125
*10^09: 3737669618.283368587493896484375
*10^10: 37376696182.83368682861328125
*10^11: 373766961828.33685302734375
*10^12: 3737669618283.36865234375
*10^13: 37376696182833.6875
*10^14: 373766961828336.8125
*10^15: 3737669618283368.5
*10^16: 37376696182833688
*10^17: 373766961828336832
*10^18: 3737669618283368448
*10^19: 37376696182833684480
*10^20: 373766961828336828416
What is Perl's greatest precision for fixed decimal numbers?
Perl doesn't have fixed point decimal numbers. Very few languages do, actually. You could use a module like Math::FixedPoint, though
Perl is storing your values as floating-point numbers internally.1 The precision is dependent on how your version of Perl is compiled, but it's probably a 64-bit double.
C:\>perl -MConfig -E "say $Config::Config{doublesize}"
8
A 64-bit double-precision float2 has a 53-bit significand (a.k.a. fraction or mantissa) which gives it approximately 16 decimal characters of precision. Your database is defined as storing 25 characters of precision. You'll be fine if you treat the data as a string but if you treat it as a number you'll lose precision.
Perl's bignum pragma provides transparent support for arbitrarily large numbers. It can slow things down considerably so limit its use to the smallest possible scope. If you want big floats only (without making other numeric types "big") use Math::BigFloat instead.
1. Internally, perl uses a datatype called an SV that can hold floats, ints, and/or strings simultaneously.
2. Assuming IEEE 754 format.
Alternatively, if you're just transferring the values from the database to a text file and not operating on them as numbers, then have the DB format them as strings. Then read and print them as strings (perhaps using "printf '%s'"). For example:
select Big_fixed_point_col(format '-Z(24)9.9(5)')(CHAR(32))

fortran90 reading array with real numbers

I have a list of real data in a file. The real data looks like this..
25.935
25.550
24.274
29.936
23.122
27.360
28.154
24.320
28.613
27.601
29.948
29.367
I write fortran90 code to read this data into an array as below:
PROGRAM autocorr
implicit none
INTEGER, PARAMETER :: TRUN=4000,TCOR=1800
real,dimension(TRUN) :: angle
real :: temp, temp2, average1, average2
integer :: i, j, p, q, k, count1, t, count2
REAL, DIMENSION(0:TCOR) :: ACF
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
open(100, file="fort.64",status="old")
do k = 1,TRUN
read(100,*) angle(k)
end do
Then, when I print again to see the values, I get
25.934999
25.549999
24.274000
29.936001
23.122000
27.360001
28.153999
24.320000
28.613001
27.601000
29.948000
29.367001
32.122002
33.818001
21.837000
29.283001
26.489000
24.010000
27.698000
30.799999
36.157001
29.034000
34.700001
26.058001
29.114000
24.177000
25.209000
25.820999
26.620001
29.761000
May I know why the values are now 6 decimal points?
How to avoid this effect so that it doesn't affect the calculation results?
Appreciate any help.
Thanks
You don't show the statement you use to write the values out again. I suspect, therefore, that you've used Fortran's list-directed output, something like this
write(output_unit,*) angle(k)
If you have done this you have surrendered the control of how many digits the program displays to the compiler. That's what the use of * in place of an explicit format means, the standard says that the compiler can use any reasonable representation of the number.
What you are seeing, therefore, is your numbers displayed with 8 sf which is about what single-precision floating-point numbers provide. If you wanted to display the numbers with only 3 digits after the decimal point you could write
write(output_unit,'(f8.3)') angle(k)
or some variation thereof.
You've declared angle to be of type real; unless you've overwritten the default with a compiler flag, this means that you are using single-precision IEEE754 floating-point numbers (on anything other than an exotic computer). Bear in mind too that most real (in the mathematical sense) numbers do not have an exact representation in floating-point and that the single-precision decimal approximation to the exact number 25.935 is likely to be 25.934999; the other numbers you print seem to be the floating-point approximations to the numbers your program reads.
If you really want to compute your results with a lower precision, then you are going to have to employ some clever programming techniques.

Perl pack and unpack functions

I am trying to unpack a variable containing a string received from a spectrum analyzer:
#42404?û¢-+Ä¢-VÄ¢-oÆ¢-8æ¢-bÉ¢-ôÿ¢-+Ä¢-?Ö¢-sÉ¢-ÜÖ¢-¦ö¢-=Æ¢-8æ¢-uô¢-=Æ¢-\Å¢-uô¢-?ü¢-}¦¢-=Æ¢-)...
The format is real 32 which uses four bytes to store each value. The number #42404 represents 4 extra bytes present and 2404/4 = 601 points collected. The data starts after #42404. Now when I receive this into a string variable,
$lp = ibqry($ud,":TRAC:DATA? TRACE1;*WAI;");
I am not sure how to convert this into an array of numbers :(... Should I use something like the followin?
#dec = unpack("d", $lp);
I know this is not working, because I am not getting the right values and the number of data points for sure is not 601...
First, you have to strip the #42404 off and hope none of the following binary data happens to be an ASCII number.
$lp =~ s{^#\d+}{};
I'm not sure what format "Real 32" is, but I'm going to guess that it's a single precision floating point which is 32 bits long. Looking at the pack docs. d is "double precision float", that's 64 bits. So I'd try f which is "single precision".
#dec = unpack("f*", $lp);
Whether your data is big or little endian is a problem. d and f use your computer's native endianness. You may have to force endianness using the > and < modifiers.
#dec = unpack("f*>", $lp); # big endian
#dec = unpack("f*<", $lp); # little endian
If the first 4 encodes the number of remaining digits (2404) before the floats, then something like this might work:
my #dec = unpack "x a/x f>*", $lp;
The x skips the leading #, the a/x reads one digit and skips that many characters after it, and the f>* parses the remaining string as a sequence of 32-bit big-endian floats. (If the output looks weird, try using f<* instead.)

script for simple math fixing input/output size

Looking for an utility or script to do some simple math in hex, decimal or binary (+ - / x) but I want to define the format and size/signal/integer ... of output. For example 0xffff + 1 will have different results if the output goes to an U16 or U32. maybe there is a tool in the web for that or somebody already did something related.
Perl has a bit-wise AND operator (&) (see Bitwise-And in perlop) which can be used to limit an integer to 16 bits. It also has sprintf and hex to perform conversions.
Well perl has a powerful math library Math::BigRat.
see here:
http://perldoc.perl.org/Math/BigRat.html
but for U16 or U32 i don't have any idea

Performing math operations on very large numbers in Perl

I have a case where some values in a data file have 64 bit wrap around which makes them very large, like, 18446744073709551608.
So I have to perform a subtraction from 2^64. I tried this using the simple
2^64 - 18446744073709551608
But I guess this number is too large and don't get the actual answer 8. What do I need to do to perform this substraction.
Check out the bignum pragma:
use bignum;
print 2**64 - 18446744073709551608;
This should properly print 8.
Note that bignum is just a layer that makes all constant numbers automatically Math::BigFloat or Math::BigInt objects. If you only want this for some numbers, you can either specify the use bignum; in a restricted scope, add no bignum; in places, or explicitly use Math::BigFloat->new('your constant') (or BigInt) to make particular numbers and the results of any operations involving them big.
use bignum ;
print 2**64 - 18446744073709551608 ,"\n" ;
in perl language , ^ = ** , mod = %
good luck !