$ echo 0.4970436865354813 | awk -v CONVFMT=%.17g '{gsub($1, $1*1.1)}; {print}'
0.54674805518902947

Or rather here:

$ echo 0.4970436865354813 | awk '{printf "%.17g\n", $1*1.1}'
0.54674805518902947

is probably the best you can achieve. Use bc instead for arbitrary precision.

$ echo '0.4970436865354813 * 1.1' | bc -l
.54674805518902943
Answer from Stéphane Chazelas on Stack Exchange
Top answer
1 of 3
22
$ echo 0.4970436865354813 | awk -v CONVFMT=%.17g '{gsub($1, $1*1.1)}; {print}'
0.54674805518902947

Or rather here:

$ echo 0.4970436865354813 | awk '{printf "%.17g\n", $1*1.1}'
0.54674805518902947

is probably the best you can achieve. Use bc instead for arbitrary precision.

$ echo '0.4970436865354813 * 1.1' | bc -l
.54674805518902943
2 of 3
7

For higher precision with (GNU) awk (with bignum compiled in) use:

$ echo '0.4970436865354813' | awk -M -v PREC=100 '{printf("%.18f\n", $1)}'
0.497043686535481300

The PREC=100 means 100 bits instead of the default 53 bits.
If that awk is not available, use bc

$ echo '0.4970436865354813*1.1' | bc -l
.54674805518902943

Or you will need to learn to live with the inherent imprecision of floats.


In your original lines there are several issues:

  • A factor of 1.1 is 10% increase, not 1% (should be a 1.01 multiplier). I'll use 10%.
  • The conversion format from a string to a (floating) number is given by CONVFMT. Its default value is %.6g. That limits the values to 6 decimal digits (after the dot). That is applied to the result of the gsub change of $1.

    $ a='0.4970436865354813'
    $ echo "$a" | awk '{printf("%.16f\n", $1*1.1)}'
    0.5467480551890295
    
    $ echo "$a" | awk '{gsub(1*1.1)}; {printf("%.16f\n", $1)}'
    0.5467480000000000
    
  • The printf format g removes trailing zeros:

    $ echo "$a" | awk '{gsub(1*1.1)}; {printf("%.16g\n", $1)}'
    0.546748
    
    $ echo "$a" | awk '{gsub(1*1.1)}; {printf("%.17g\n", $1)}'
    0.54674800000000001
    

    Both issues could be solved with:

    $ echo "$a" | awk '{printf("%.17g\n", $1*1.1)}'
    0.54674805518902947
    

    Or

    $ echo "$a" | awk -v CONVFMT=%.30g '{gsub(1*1.1)}; {printf("%.17f\n", $1)}'
    0.54674805518902947 
    

But don't get the idea that this means higher precision. The internal number representation is still a float in double size. That means 53 bits of precision and with that you could only be sure of 15 correct decimal digits, even if many times up to 17 digits look correct. That's a mirage.

$ echo "$a" | awk -v CONVFMT=%.30g '{gsub(1*1.1}; {printf("%.30f\n", $1)}'
0.546748055189029469325134868996

The correct value is:

$ echo "scale=18; 0.4970436865354813 * 1.1" | bc
.54674805518902943

Which could be also calculated with (GNU) awk if the bignum library has been compiled in:

$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g '{printf("%.30f\n", $1)}'
0.497043686535481300000000000000
🌐
GNU
gnu.org › software › gawk › manual › html_node › Setting-precision.html
Setting precision (The GNU Awk User’s Guide)
$ gawk -M 'BEGIN { PREC = 113; printf("%0.25f\n", 0.1) }' -| 0.1000000000000000055511151 $ gawk -M -v PREC=113 'BEGIN { printf("%0.25f\n", 0.1) }' -| 0.1000000000000000000000000 $ gawk -M 'BEGIN { PREC = 113; printf("%0.25f\n", "0.1") }' -| 0.1000000000000000000000000 $ gawk -M 'BEGIN { PREC = 113; printf("%0.25f\n", 1/10) }' -| 0.1000000000000000000000000 · Next: Setting the Rounding Mode, Previous: Try a Few Extra Bits of Precision and Rounding, Up: Floating-Point Arithmetic: Caveat Emptor!
Discussions

floating point calculations in awk - Stack Overflow
I am surprised with behaviour of awk while performing floating point calculations. It lead me to wrong calculation on table data. $ awk 'BEGIN {print 2.3/0.1}' 23 More on stackoverflow.com
🌐 stackoverflow.com
How To Work With Large Floating Point Numbers In AWK?
Numbers don't "turn into" scientific numbers. That is an artefact of the printf default format when you display them. If you allow them more precision, you will get more digits. Awk stores all numbers as IEEE 64-bit (double) precision. Typically, the default is to show you no more than six digits after the decimal point. GNU/awk does have an inbuilt high-precision library (it is a compile-time option, so check your gawk has it). Take a look at: https://www.gnu.org/software/gawk/manual/gawk.html#MPFR-features More on reddit.com
🌐 r/bash
4
7
December 14, 2021
shell - How to print float numbers with awk - Stack Overflow
I have this input file: Adrian 20.6 Bruce 40.2 Adrian 30.4 Janick 24.2 Dave 42.7 Bruce 42.9 Janick 41.2 And with a answer I've got here, I was able to sum the numbers, but now the numbers are floa... More on stackoverflow.com
🌐 stackoverflow.com
floating point arithmetic in the shell: awk or bc?
bc doesn't do 'floating point' it does 'arbitrary precision'. The difference is often lost, but it can be important. In reality both awk and bc are just fine along with python, perl and a few other tools. The posix standard used to include dc which was a reverse-polish version of bc, but that seems to have been removed in more recent standards. If you are just doing one calculation bc is an excellent choice, it is flexible and powerful and can work to very high precision that is sometimes needed but difficult in awk. On the other hand if you are doing thousands of calculations based on the values in a table, the ability of awk to work with fields and data streams is invaluable. Like almost every task in shell, there is no 'always best' answer. You should be guided by your use case and choose the tool suitable for the job. EDIT to add a demo of the difference between awk and bc.. awk 'BEGIN{ printf "%.20f\n",1/3}' echo 'scale=20; 1/3' | bc on my system this gives different results (Yours might vary depending on the size of a float in your version of awk). If it does get the same result change the scale to 128 and obvserve the difference. More on reddit.com
🌐 r/commandline
15
8
November 22, 2022
Top answer
1 of 2
3

you can control the number of decimal points with printf, eventually though the numbers won't be significant due to floating point representation

for example

awk 'BEGIN{for(i=5;i<20;i++) printf "%."i"f\n", 1./3}'

0.33333
0.333333
0.3333333
0.33333333
0.333333333
0.3333333333
0.33333333333
0.333333333333
0.3333333333333
0.33333333333333
0.333333333333333
0.3333333333333333
0.33333333333333331
0.333333333333333315
0.3333333333333333148
2 of 2
2

To complement karakfa's helpful answer:

In addition to explicit number formatting with printf and sprintf, you can also change awk's default floating-point number formatting, via built-in variable OFMT.
Note that it does not apply to integers.

OFMT defaults to %.6g, which means that any floating-point number is rounded to 6 significant digits and for exponents starting with 7 is represented in scientific notation.

Calculation result 1887436.8 - which has 8 significant digits - is therefore represented as 1.88744e+06, i.e., in scientific notation with 6 significant digits.

The following example sets OFMT to %1.f in order to output all floating-point numbers with 1 decimal place by default:

$ awk -v OFMT='%.1f' 'BEGIN {ram=(1.8 * 1024) * 1024; print ram}'
1887436.8

Note, however, that OFMT does not apply in the following scenarios:

  • If the floating-point number is used in a string concatenation:

    $ awk -v OFMT='%.1f' 'BEGIN { print "result: " 1 / 3 }'
    result: 0.333333
    
    # Workaround: Use `sprintf()` with OFMT
    awk -v OFMT='%.1f' 'BEGIN { print "result: " sprintf(OFMT, 1 / 3) }'
    result: 0.3
    
  • If a literal can be parsed as an integer - even if it looks like a floating-point number:

    $ awk -v OFMT='%.1f' 'BEGIN { print 1.000 }'
    1
    

Caveat: There are many subtleties around number conversion and formatting in awk, not least because of the limited precision of floating-point numbers (which in awk are always of the ISO C double type).

🌐
Northern Illinois University
faculty.cs.niu.edu › ~berezin › 330 › N › awk-printing.html
https://faculty.cs.niu.edu/~berezin/330/N/awk-prin...
There are several 'issues' with this, text is right justified, several of the floats are still not aligned. The -, minus, can be used to left justify the text. And the default size for both data fields can be increased. awk '{ printf ( "%-14s %8.3f\n", $1, $2 ); }' data
🌐
Reddit
reddit.com › r/bash › how to work with large floating point numbers in awk?
r/bash on Reddit: How To Work With Large Floating Point Numbers In AWK?
December 14, 2021 -

I've noticed that in AWK, whenever you deal with numbers with a lot of digits and a decimal value.....it will round it off or sometimes even just turn it into an integer.

I don't notice this happening with smaller decimal numbers.

Is there a way around this? Maybe a tool? I know you can just multiply the numbers by powers of 10 to temporarily turn it into an integer, and then turn it back into decimal........but the problem with that is that if the numbers get really big, they turn into scientific numbers.

So is there any way to just keep them the way they are and deal with them?

I know of the BC tool in bash (which lets you work with floating point numbers because bash is designed to handle integers). But I don't know how to do this in AWK.

🌐
LBL
bl831.als.lbl.gov › ~gmeigs › scripting_help › printf_awk_notes.txt
-->>> List of the format-control letters:
`.prec' This is a number that specifies the precision to use when printing. This specifies the number of digits you want printed to the right of the decimal point. For a string, it specifies the maximum number of characters from the string that should be printed. printf "%.3f\n", 123.4567 prints `123.457 3 (rounded) digits after the decimal · ########################################## --->>> Padding Zeros ... echo 123.4567 | awk '{printf "%8.1f\n", $1}' 123.5 echo 123.4567 | awk '{printf "%8.6f\n", $1}' 123.456700
Top answer
1 of 2
7

You're in a locale where the decimal separator is not . so the . is being treated as any other character that's not part of a number (e.g. a or @) and so your numbers are being truncated to the part before the ..

Do LC_ALL=C awk '...' to set your locale to one that does use a . for the decimal separator and then your script will work as-is.

2 of 2
2

I think you are closer than you think, but your problems stem from not handling putting the pieces together in the right order. By default awk handles floating-point math. Your summation of sum[$1] += $2 will be done with floating point numbers if your input numbers contains decimal places.

Why you are using a Command Substitution, e.g. $(..) is unclear. That isn't needed to fill temp.txt with the sorted sums from your input. Let's take for example your input file in a file named input. Then to sum and output the values you need nothing more than:

awk '{sum[2} END {for (i in sum) print i, sum[i]}' input

Which results in the output of:

Bruce 83.1
Dave 42.7
Adrian 51
Janick 65.4

To sort the results, simply pipe the awk output to sort, e.g.

awk '{sum[2} END {for (i in sum) print i, sum[i]}' input | sort

Result:

Adrian 51
Bruce 83.1
Dave 42.7
Janick 65.4

Now, to fill temp.txt, you simply need to redirect the output to temp.txt, e.g.

awk '{sum[2} END {for (i in sum) print i, sum[i]}' input | sort > temp.txt

temp.txt now contains the sorted output. To nicely tabularize the output, you can format the output by saving the max length for $1 and setting the name field-width to max and then outputting the floating-point number in a fixed format (total floating-point field-width 10 with 1 digit following the decimal point), e.g.

{sum[$1] += $2; len=length($1); if(len>max)max=len} ...  printf "%-*s%10.1f\n", max, i, sum[i]

Or in full-form:

awk '{sum[2; len=length($1); if(len>max)max=len} END {for (i in sum) printf "%-*s%10.1f\n", max, i, sum[i]}' input | sort > temp.txt

With the results in temp.txt now being:

$ cat temp.txt
Adrian      51.0
Bruce       83.1
Dave        42.7
Janick      65.4
Find elsewhere
🌐
Reddit
reddit.com › r/commandline › floating point arithmetic in the shell: awk or bc?
r/commandline on Reddit: floating point arithmetic in the shell: awk or bc?
November 22, 2022 -

Dear all,

I am writing again to seek your help regarding POSIX shell scripting.

Since the standard does not define FP arithmetic directly in the shell, we need an external tool to compute. The two primary candidates are awk and bc/dc.

If you have experience with FP in the shell, which do you think is more appropriate, or if there are different situations for each, what are the main difference? When does it make sense to user one over the other?

Also, if I have missed another POSIX utility that can be used, let me know!

Thank you for your time!

🌐
Wikibooks
en.wikibooks.org › wiki › An_Awk_Primer › Output_with_print_and_printf
An Awk Primer/Output with print and printf - Wikibooks, open books for an open world
The fractional part of the number specifies either, for a string, the maximum number of characters to be printed; or, for floating-point formats, the number of digits to be printed to the right of the decimal point.
🌐
GNU Project
gnu.ist.utl.pt › software › gawk › manual › html_node › Floating-Point-Issues.html
Floating Point Issues - The GNU Awk User's Guide
As mentioned earlier, floating-point numbers represent what are called “real” numbers, i.e., those that have a fractional part. awk uses double-precision floating-point numbers to represent all numeric values.
🌐
Unix.com
unix.com › shell programming and scripting
How to format the output using float in awk{printf} - Shell Programming and Scripting - Unix Linux Community
October 18, 2017 - Hi I'm using awk to manipulate the data in the 6th field of the file xxx_yyy.hrv. The sample data that is available in this field is given below 220731.7100000000000000 When i tried using this command cat xxx_yyy.hrv | awk '{printf("#.16f\n",$6*-1)}' I get the output as -220731.7099999999991269 but i need the output as -220731.7100000000000000 Plz let me know on the format that i should be using to retreive the desired output.
🌐
Apprize
apprize.best › programming › awk › 17.html
Arithmetic and Arbitrary-Precision Arithmetic with gawk - Moving Beyond Standard awk with gawk - Effective awk Programming (2015)
Three of the standard IEEE 754 ... formats to allow greater precisions and larger exponent ranges. (awk uses only the 64-bit double-precision format.)...
🌐
GNU
gnu.org › software › gawk › manual › html_node › Format-Modifiers.html
Format Modifiers (The GNU Awk User’s Guide)
A period followed by an integer constant specifies the precision to use when printing.
🌐
nixCraft
cyberciti.biz › nixcraft › howto › bash shell › awk floating point number addition results are unexpected
Awk Floating Point Number Addition Results Are Unexpected - nixCraft
July 29, 2013 - grep ‘foo’ 2012-2013.txt | ... +=$7}END{ print “$” sum}’ $682444 · I want $682444.57 as output. How can I force “awk” to do floating point math? Floating-point numbers or “real” numbers are that have a fractional part. awk uses double-precision floating-point ...
🌐
Unix.com
unix.com › shell programming and scripting
Four decimal places with awk - Shell Programming and Scripting - Unix Linux Community
October 18, 2017 - i have a script in which awk prints "($2-1700)/10000" and the answer is -0.07,but i want the answer in 4 decimal places. that is -0.0700. How can i sue awk to get my results in four decimal places