script for simple math fixing input/output size - perl

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

Related

How would you write a SystemVerilog Function that adds an even parity bit to a 7-bit vector?

Would you take a 7-bit logic variable as an input and return an 8-bit logic output with the parity bit being the MSB (leftmost bit) of the output?
In a system that uses even parity you want the total number of 1 bits in the output vector to be even, right?
Can the the unary ^ operator can be used to calculate even parity?
Trying to figure out what that would look like?
I started something like this:
Code for parity
Sorry if this is more than one question.
I would do this like this:
input logic [N-1:0] data_in;
output logic [N:0] data_out;
assign data_out = {^data_in, data_in};
The ^ reduction operator does an XOR operation on all the bits in the operand. (So, it will return '1 if data_in has an odd number of ones.)

Convert Integer in to decimal 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.

Discrepancy in !objsize in hex and decimal

I use !objsize command to get the true value of an object. For example when I run the command below, it tells me that size of object at address 00000003a275f218 is 18 hex which translates to 24 in decimal.
0:000> !ObjSize 00000003a275f218
sizeof(00000003a275f218) = 24 (0x18) bytes
So far so good. I am running same command on an object and its size seem to have a discrepancy between hex and decimal.
So the size in hex is 0xafbde200. When I convert it to decimal using my calc, this comes to be 2948456960 whereas the output of command is showing decimal size to be -1346510336. Can someone help me understand why there is difference in sizes?
It's a bug in SOS. If you look at the source code, you'll find the method declared as
DECLARE_API(ObjSize)
It uses the following format as output
ExtOut("sizeof(%p) = %d (0x%x) bytes (%S)\n", SOS_PTR(obj), size, size, methodTable.GetName());
As you can see it uses %d as the format specifier, which is for signed decimal integers. That should be %u for unsigned decimal integers instead, since obviously you can't have objects using negative amount of memory.
If you know how to use Git, you may provide a patch.
You can use ? in WinDbg to see the unsigned value:
0:000> ? 0xafbde200
Evaluate expression: 2948456960 = 00000000`afbde200
Difference is the sign. It seems to be interpreting the first bit (which is 1 since the first hex byte is "A") as a negative sign. These two numbers are otherwise the same.
Paste -1346510336 on calc.exe (programmer mode), switch to Hex:
FFFFFFFFAFBDE200
Paste 2948456960, switch to Hex:
AFBDE200

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))

Perl for loop going haywire [duplicate]

This question already has answers here:
Does scientific notation affect Perl's precision?
(1 answer)
Perl int function and padding zeros
(2 answers)
Closed 10 years ago.
I have a simple for loop in Perl
for ($i=0; $i <= 360; $i += 0.01)
{
print "$i ";
}
Why is it that when I run this code I get the following output, where as soon as it gets to 0.81 it suddenly starts to add in a load more decimal places? I know I could simply round up to avoid this issue but I was wondering why it happens. An increment of 0.01 does not seem at all crazy to do.
0.77
0.78
0.79
0.8
0.81
0.820000000000001
0.830000000000001
0.840000000000001
0.850000000000001
0.860000000000001
0.870000000000001
Computers use binary representations. Not all decimal floating point numbers have exact representations in binary notation, so some error can occur (its actually a rounding difference). This is the same reason why you shouldn't use floating point numbers for monetary values:
(Picture taken from dailywtf)
Most elegant way to get around this issue is using integers for calculations, dividing them to the correct number of decimal places and using sprintf to limit the number of decimal places printed. This will both make sure:
There's always to correct result printed
The rounding error doesn't accumulate
Try this code:
#!/usr/bin/perl
for ($i=0; $i <= 360*100; $i += 1) {
printf "%.2f \n", $i/100;
}
Basically, because the decimal number 0.01 does not have an exact representation in binary floating point, so over time, adding the best approximation to 0.01 deviates from the answer you'd like.
This is basic property of (binary) floating point arithmetic and not peculiar to Perl. What Every Computer Scientist Should Know About Floating-Point Arithmetic is the standard reference, and you can find it very easily with a Google search.
See also: C compiler bug (floating point arithmetic) and no doubt a myriad other questions.
Kernighan & Plauger say, in their old but classic book "The Elements of Programming Style", that:
A wise old programmer once said "floating point numbers are like little piles of sand; every time you move one, you lose a little sand and gain a little dirt".
They also say:
10 * 0.1 is hardly ever 1.0
Both sayings point out that floating point arithmetic is not precise.
Note that some modern CPUs (IBM PowerPC) have IEEE 754:2008 decimal floating point arithmetic built-in. If Perl used the correct types (it probably doesn't), then your calculation would be exact.
To demonstrate Jonathan's answer, if you code up the same loop structure in C, you will get the same results. Although C and Perl may compile differently and be ran on different machines the underlying floating point arithmetic rules should cause consistent outputs. Note: Perl uses double-precision floating point for its floating point representation whereas in C the coder explicitly chooses float or double.
Loop in C:
#include <stdio.h>
int main() {
double i;
for(i=0;i<=1;i+=.01) {
printf("%.15f\n",i);
}
}
Output:
0.790000000000000
0.800000000000000
0.810000000000000
0.820000000000001
0.830000000000001
0.840000000000001
0.850000000000001
To demonstrate the point even further, code the loop in C but now use single-precision floating point arithmetic and see that the output is less precise and even more erratic.
Output:
0.000000000000000
0.009999999776483
0.019999999552965
0.029999999329448
0.039999999105930
0.050000000745058
0.060000002384186
0.070000000298023
0.079999998211861
0.089999996125698
0.099999994039536
1/10 is periodic in binary just like 1/3 is periodic in decimal. As such, it cannot be accurately stored in a floating point number.
>perl -E"say sprintf '%.17f', 0.1"
0.10000000000000001
Either work with integers
for (0*100..360*100) {
my $i = $_/100;
print "$i ";
}
Or do lots of rounding
for (my $i=0; $i <= 360; $i = sprintf('%.2f', $i + 0.01)) {
print "$i ";
}