Adding two numbers in unix - sh

I tried to add two numbers by below logic:
num=0001
newnum=`expr $num + 1`
echo $newnum
But it returns '2', my desired output is '0002'.
num=0001
newnum=`expr $num + 0001`
echo $newnum
I used above logic also,but no use. What is needed here to get my desired output.
Thanks in advance.

Use printf to print numbers with leading zeroes:
printf "%04d\n" $num
You shouldn't do arithmetic with numbers with leading zeroes, because many applications treat an initial zero as meaning that the number is octal, not decimal.

Use printf:
$ num=0001
$ printf "%04d" $(expr $num + 1)
0002
In order to assign the result to a variable, say:
$ newnum=$(printf "%04d" $(expr $num + 1))
$ echo $newnum
0002

Numbers with leading zeros are interpreted as octal numbers. In order to treat them as decimals you need to prepend 10# to the number. Finally, use printf to pad the number with zeros.
num=0001
newNum=$((10#$num + 1))
paddedNum=$(printf %04d $newNum)

Related

Remove upfront zeros from floating point lower than 1 in Perl

I would like to normalize the variable from ie. 00000000.1, to 0.1 using Perl
my $number = 000000.1;
$number =\~ s/^0+(\.\d+)/0$1/;
Is there any other solution to normalize floats lower than 1 by removing upfront zeros than using regex?
When I try to put those kind of numbers into an example function below
test(00000000.1, 0000000.025);
sub test {
my ($a, $b) = #_;
print $a, "\n";
print $b, "\n";
print $a + $b, "\n";
}
I get
01
021
22
which is not what is expected.
A number with leading zeros is interpreted as octal, e.g. 000000.1 is 01. I presume you have a string as input, e.g. my $number = "000000.1". With this your regex is:
my $number = "000000.1";
$number =~ s/^0+(?=0\.\d+)//;
print $number;
Output:
0.1
Explanation of regex:
^0+ -- 1+ 0 digits
(?=0\.\d+) -- positive lookahead for 0. followed by digits
Learn more about regex: https://twiki.org/cgi-bin/view/Codev/TWikiPresentation2018x10x14Regex
Simplest way, force it to be treated as a number and it will drop the leading zeros since they are meaningless for decimal numbers
my $str = '000.1';
...
my $num = 0 + $str;
An example,† to run from the command-line:
perl -wE'$n = shift; $n = 0 + $n; say $n' 000.1
Prints 0.1
Another, more "proper" way is to format that string ('000.1' and such) using sprintf. Then you do need to make a choice about precision, but that is often a good idea anyway
my $num = sprintf "%f", $str; # default precision
Or, if you know how many decimal places you want to keep
my $num = sprintf "%.3f", $str;
† The example in the question is really invalid. An unquoted string of digits which starts with a zero (077, rather than '077') would be treated as an octal number except that the decimal point (in 000.1) renders that moot as octals can't be fractional; so, Perl being Perl, it is tortured into a number somehow, but possibly yielding unintended values.
I am not sure how one could get an actual input like that. If 000.1 is read from a file or from the command-line or from STDIN ... it will be a string, an equivalent of assigning '000.1'
See Scalar value constructors in perldata, and for far more detail, perlnumber.
As others have noted, in Perl, leading zeros produce octal numbers; 10 is just a decimal number ten but 010 is equal to decimal eight. So yeah, the numbers should be in quotes for the problem to make any sense.
But the other answers don’t explain why the printed results look funny. Contrary to Peter Thoeny’s comment and zdim’s answer, there is nothing ‘invalid’ about the numbers. True, octals can’t be floating point, but Perl does not strip the . to turn 0000000.025 into 025. What happens is this:
Perl reads the run of zeros and recognises it as an octal number.
Perl reads the dot and parses it as the concatenation operator.
Perl reads 025 and again recognises it as an octal number.
Perl coerces the operands to strings, i.e. the decimal value of the numbers in string form; 0000000 is, of course, '0' and 025 is '21'.
Perl concatenates the two strings and returns the result, i.e. '021'.
And without error.
(As an exercise, you can check something like 010.025 which, for the same reason, turns into '821'.)
This is why $a and $b are each printed with a leading zero. Also note that, to evaluate $a + $b, Perl coerces the strings to numbers, but since leading zeros in strings do not produce octals, '01' + '021' is the same as '1' + '21', returning 22.

How to preserve number of decimal places in perl after multiplication

I have one floating point number in Perl and after multiplying with negative integer, all trailing zeroes are getting removed automatically. However I still need those extra zeroes.
Example:
my $float = 1.40000;
my $multiply = -1 * $float;
print "Negative number: $multiply"; //-1.4
Is there any way to get -1.40000?
You need to format your output using printf.
printf( "Negative number: %.4f\n", $multiply );
Learn more about printf with perldoc -f printf or here.

bug in perl with prefixed 0 numbers

when I try to execute the following(01434.210 instead of 1434.210)
$val=22749.220-(21315.010+01434.210)
print $val
I get these output
output 638.207900000001
But according to me output must be 0.
What am I missing?
A leading 0 in a literal number makes Perl interpret the value I'm base 8:
123 # 123, in decimal
0123 # 123 in octal, but 83 in decimal
This isn't the same for strings converted to numbers. In those Perl ignores the leading 0s. The string-to-number conversion only deals in base-10:
"123" + 0 # 123
"0123" + 0 # still 123
In your example in the comment, you convert a literal number to a string with a leading zero. When you convert that string back to its numeric form you get the same value you started with:
$val=sprintf("%05d",1434); # converting 1434 to the string "01434"
print $val; print "\n"; # still a string
print $val+21315; # "01434" + 21315 => 1434 + 21315
print "\n";
print 01434+21315; # oct(1434) + 21315 => 796 + 21315
The leading zero notation helps with certain builtins that typically use octal numbers, such as those that deal with unix permissions:
chmod 0644, #files

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.

How do I increment a value with leading zeroes in Perl?

It's the same question as this one, but using Perl!
I would like to iterate over a value with just one leading zero.
The equivalent in shell would be:
for i in $(seq -w 01 99) ; do echo $i ; done
Since the leading zero is significant, presumably you want to use these as strings, not numbers. In that case, there is a different solution that does not involve sprintf:
for my $i ("00" .. "99") {
print "$i\n";
}
Try something like this:
foreach (1 .. 99) {
$s = sprintf("%02d",$_);
print "$s\n";
}
The .. is called the Range Operator and can do different things depending on its context. We're using it here in a list context so it counts up by ones from the left value to the right value. So here's a simpler example of it being used; this code:
#list = 1 .. 10;
print "#list";
has this output:
1 2 3 4 5 6 7 8 9 10
The sprintf function allows us to format output. The format string %02d is broken down as follows:
% - start of the format string
0 - use leading zeroes
2 - at least two characters wide
d - format value as a signed integer.
So %02d is what turns 2 into 02.
printf("%02d\n",$_) foreach (1..20)
print foreach ("001" .. "099")
foreach $i (1..99) {printf "%02d\n", $i;}
I would consider to use sprinft to format $i according to your requirements. E.g. printf '<%06s>', 12; prints <000012>.
Check Perl doc about sprinft in case you are unsure.
Well, if we're golfing, why not:
say for "01".."99"`
(assuming you're using 5.10 and have done a use 5.010 at the top of your program, of course.)
And if you do it straight from the shell, it'd be:
perl -E "say for '01'..'99'"