C descriptor for double on Linux - double

What is the Descriptor for double in C? When I use
printf("%d",x)
and x is a double variable it says a warning that it %d expects an int argument, while x is double.

printf("%f", x);
When x is a double variable.

There are quite a number of format specifiers for printf. Here are the basic ones :
%d print an int argument in decimal
%ld print a long int argument in decimal
%c print a character
%s print a string
%f print a float or double argument
%e same as %f, but use exponential notation
%g use %e or %f, whichever is better
%o print an int argument in octal (base 8)
%x print an int argument in hexadecimal (base 16)
%% print a single %

Related

Negative representation of Perl hex number is always sign-extended to 8 bytes

I am using sprintf in Perl to convert decimal numbers to their hex equivalents, as in:
my $positive = sprintf("X'%02X'", 1); # X'01'
my $negative = sprintf("X'%02X'", -1); # X'FFFFFFFFFFFFFFFF'
Why does the negative number always get sign-extended to the 8-byte representation of the number, even if the precision specified in sprintf is smaller?
Is there a way to avoid this so I don't have to substring the value every time? The same result occurs even if I remove the 0, as in: sprintf("X'%2X'", -1).
Well, %x specifically takes an unsigned integer, so when you give it the bit pattern for a signed integer, it treats all of those bits as an unsigned one. The length of the output probably depends on how big your compiler made numbers (although I'm guessing most modern things are the same now). Perl stores most of its numbers as doubles, so that's the size of the number. It's one of few places where Perl exposes the underlying architecture.
This means that you need to handle the sign yourself and use the absolute value of the number:
sprintf( "%s%2x", ($n < 0 ? '-' : ''), abs($n) );
As for the sprintf field specifiers, you are not specifying a precision there. That's minimum width. The %f and %g specifiers may have a maximum number of decimal places, but the entire string can still overflow.
But, it turns out that your problem is different. You want the values from -128 to 127 it their signed integer form. So, -1 gets FF. You need to add a little bit to get that.
my $s = sprintf( "%2x", $n );
$s = substr( $s, -2 ) if $n < 0;

Perl inconsistently prints strings that contain specific combinations of '%'

Can anyone please explain this perl behavior that i came across?
printf("%what_the\n");
printf("\%what_the\n");
Prints:
%what_the
%what_the
WHILE...
printf("%tomorrow\n");
printf("\%tomorrow\n");
Prints:
0morrow
0morrow
...EVEN WITH warnings and strict:
use strict;
use warnings;
printf("\%tomorrow\n");
Prints:
Missing argument in printf at - line 3.
0morrow
printf is different from regular print. You might be thinking it is the same, it is not. printf takes a pattern, which includes %. For example:
printf "%s\n", "tomorrow"; # prints "tomorrow\n"
%s is a placeholder for a string, which should be the second argument to printf.
The warning you get shows you the problem
Missing argument in printf at - line 3.
printf expects a second argument, because you have supplied a placeholder.
Not all letters following a percent sign is a valid combination, here's a few from the documentation from sprintf
%% a percent sign
%c a character with the given number
%s a string
%d a signed integer, in decimal
%u an unsigned integer, in decimal
%o an unsigned integer, in octal
%x an unsigned integer, in hexadecimal
%e a floating-point number, in scientific notation
%f a floating-point number, in fixed decimal notation
%g a floating-point number, in %e or %f notation
.... more
I do not see %to in there, but it seems to be what is being triggered. It prints a 0 because it casts the empty string (missing argument) to 0.
Documentation here.
The way to escape a % sign is to double it, not by a backslash. %o is the format for printing an octal number. Try doing printf "%tomorrow", 255;. The t is a modifier flag on %o to set the integer type.
https://perldoc.perl.org/functions/sprintf#size
HTH

Is %s the only format that will allow printf to display big integers correctly?

I just spent an epoch figuring out that my big integer was fine and that printf's %d/%u were not up to the task of displaying it:
use strict;
use warnings;
use bigint;
use List::Gen;
*factorial = do {use bigint; <[..*] 1, 1..>->code};
my $value = factorial(32);
printf "%d\n", $value; # -1
printf "%u\n", $value; # 18446744073709551615
printf "%s\n", $value; # 263130836933693530167218012160000000
I wouldn't be surprised if the answer is no, just wanted to confirm it.
This was surprisingly hard to track down. I didn't see anything obvious in the docs, so I went to the source. The printf function is implemented (at the bottom of a long call stack) by the C function Perl_sv_vcatpvfn_flags. It appears as if this function assumes the number will fit in an IV or a UV. They are defined by
typedef IVTYPE IV;
typedef UVTYPE UV;
Which is in turn defined by (at least on my Perl, I think this is configurable)
#define IVTYPE long /**/
#define UVTYPE unsigned long /**/
So, if your number won't fit in a long, then (%d) or in an unsigned long (%u), then a string (%s) is your only option. A bigger quesiton is why you are using printf in the first place. Are you formatting these numbers in some way other than printing them? If not, then print should just do the right thing.
Yes. %s is the only format for strings.
%%: Obviously no.
%c: Obviously no.
%s: Yes.
%d: Only if the number fits in a signed integer.
%u, %o, %x, %X, %b, %B: Only if the number fits in a unsigned integer.
%e, %E, %f, %g, %G, %a, %A: Only if the number fits in a floating point number.
%p: Obviously no.
%n: Obviously no.
Given that you have to use a specific library for the purpose of manipulating such numbers, there is no reason to expect that the builtin printf would handle them. Instead, you can use the library's conversion functions such as as_hex or bnstr. If you just want to print the number, use print "$value\n";.

Convert decimal number to hexadecimal in perl in specific format

initialize a scalar variable with an integer value
my $dec = 1211;
print "Hexadecimal number: ", uc(sprintf("%x\n", $dec)), "\n";
displays 4BB
But how can i get the output in 000004BB ormat.
Use a length specifier with leading zeroes:
sprintf('%08X', $dec)
Also, you don't need to use the uc() function: just use the %X (capital-X) format character.
To print the heading as well:
printf "Hexadecimal number: %08X\n", $dec

Perl - Remove trailing zeroes without exponential value

I am trying to remove trailing zeroes from decimal numbers.
For eg: If the input number is 0.0002340000, I would like the output to be 0.000234
I am using sprintf("%g",$number), but that works for the most part, except sometimes it converts the number into an exponential value with E-. How can I have it only display as a full decimal number?
Numbers don't have trailing zeroes. Trailing zeroes can only occur once you represent the number in decimal, a string. So the first step is to convert the number to a string if it's not already.
my $s = sprintf("%.10f", $n);
(The solution is suppose to work with the OP's inputs, and his inputs appear to have 10 decimal places. If you want more digits to appear, use the number of decimal places you want to appear instead of 10. I thought this was obvious. If you want to be ridiculous like #asjo, use 324 decimal places for the doubles if you want to make sure not to lose any precision you didn't already lose.)
Then you can delete the trailing zeroes.
$s =~ s/0+\z// if $s =~ /\./;
$s =~ s/\.\z//;
or
$s =~ s/\..*?\K0+\z//;
$s =~ s/\.\z//;
or
$s =~ s/\.(?:|.*[^0]\K)0*\z//;
To avoid scientific notation for numbers use the format conversion %f instead of %g.
A lazy way could be simply: $number=~s/0+$// (substitute trailing zeroes by nothing).
The solution is easier than you might think.
Instead of using %g use %f and it will result in the behavior you are looking for. %f will always output your floating decimal in "fixed decimal notation".
What does the documentation say about %g vs %f?
As you may notice in the below table %g will result in either the same as %f or %e (when appropriate).
Ff you'd want to force the use of fixed decimal notation use the appropriate format identifier, which in this case is %f.
sprintf - perldoc.perl.org
%% a percent sign
%c a character with the given number
%s a string
%d a signed integer, in decimal
%u an unsigned integer, in decimal
%o an unsigned integer, in octal
%x an unsigned integer, in hexadecimal
%e a floating-point number, in scientific notation
%f a floating-point number, in fixed decimal notation
%g a floating-point number, in %e or %f notation
What about TIMTOWTDI; aren't we writing perl?
Yes, as always there are more than one ways of doing it.
If you'd just like to trim the trailing decimal-point zeros from a string you could use a regular expression such as the below.
$number = "123000.321000";
$number =~ s/(\.\d+?)0+$/$1/;
$number # is now "12300.321"
Remember that floating point values in perl doesn't have trailing decimals, unless you are dealing with a string. With that said; a string is not a number, even though it can explicitly and implicitly be converted to one.
The simplest way is probably to multiply by 1.
Original:
my $num = sprintf("%.10f", 0.000234000001234);
print($num);
#output
0.0002340000
With multiplying:
my $num = sprintf("%.10f", 0.000234000001234) * 1;
print($num);
#output
0.000234
The whole point of the %g format is to use a fixed point notation when it is reasonable and to use exponential notation when fixed point is not reasonable. So, you need to know the range of values you'll be dealing with.
Clearly, you could write a regular expression to post-process the string from sprintf(), removing the trailing zeroes:
my $str = sprintf("%g", $number);
$str =~ s/0+$//;
If you always want a fixed point number, use '%f', possibly with number of decimal places that you want; you might still need to remove trailing zeroes. If you always want exponential notation, use '%e'.
An easy way:
You could cheat a little. Add 1 to avoid the number breaking into scientific notation. Then manipulate the number as a string (thereby making perl convert it into a string).
$n++;
$n =~ s/^(\d+)(?=\.)/$1 - 1/e;
print $n;
A "proper" way:
For a more "proper" solution, counting the number of decimal places to use with %f would be optimal. It turned out getting the correct number of decimal points is trickier than one would think. Here's an attempt:
use strict;
use warnings;
use v5.10;
my $n = 0.000000234;
say "Original: $n";
my $l = getlen($n);
printf "New : %.${l}f\n", $n;
sub getlen {
my $num = shift;
my $dec = 0;
return 0 unless $num; # no 0 values allowed
return 0 if $num >= 1; # values above 1 don't need this computation
while ($num < 1) {
$num *= 10;
$dec++;
}
$num =~ s/\d+\.?//; # must have \.? to accommodate e.g. 0.01
$dec += length $num;
return $dec;
}
Output:
Original: 2.34e-007
New : 0.000000234
The value can have trailing zeroes only if it is a string.
You can add 0 to it. It will be coverted to a numerical value, not showing any trailing zeroes.