Aashu
Aashu

Reputation: 1287

Float calculation on csv in bash

I want to eval a single column with

$(echo "1023630 / ln( 10000 /$2 )  / ( 3435 / ln( 10000 /$2 ) - 298 )" | bc -l)

but while reading a file its throwing an syntax error. How can I eval this? I have tried with

while IFS="," read a b c d; do 
    printf "%s,%s,%s,%s\n" $a $(echo "1023630 / ln( 10000 /$b )  / ( 3435 / ln( 10000 /$b ) - 298 )" | bc -l) $c $d; 
done < abcdtemp.csv 

150918021814,1421.5,1,
(sRuntime error (func=(main), adr=26): Function ln not defined.
150918021216,1421.5,1.4,

even with awk it's not working

awk -F',' -v OFS="," '{$2=$(echo "1023630/ln(10000/$2)  / (3435/ln(10000/$2)-298)" | bc -l);$3=$(echo "1023630/ln(10000/$3)  / (3435/ln(10000/$3)-298)" | bc -l);}1' file

awk -F',' -v OFS="," '{$1;$2=printf "%.1f\n","1023630/ln(10000/$2)/(3435/ln(10000/$2)-298)";$3=printf "%.1f\n","1023630/ln(10000/$2)/(3435/ln(10000/$3)-298)";}1' file

Any hint or help, what am I missing? Thanks.

Upvotes: 3

Views: 276

Answers (2)

Ed Morton
Ed Morton

Reputation: 203349

All you need is a simple awk script:

$ cat file
3,5,7,11

$ while IFS="," read a b c d; do printf "%s,%s,%s,%s\n" $a $(echo "1023630 / l( 10000 /$b ) / ( 3435 / l( 10000 /$b ) - 298 )" | bc -l) $c $d; done < file
3,874.94898530684189106603,7,11

$ awk 'BEGIN{FS=OFS=",";OFMT="%.20f"} {d=log(10000/$2); print $1, 1023630 / d / (3435/d - 298), $3, $4}' file
3,874.94898530684179149830,7,11

It's far more efficient, robust, portable, and better in every other way than a shell loop. Differences in output value after the 12th decimal place presumably irrelevant and due to floating point arithmetic differences between the tools.

If you're not convinced, look at how long each command takes to execute when run on a file that's just 1,000 lines long,

$ time while IFS="," read a b c d; do printf "%s,%s,%s,%s\n" $a $(echo "1023630 / l( 10000 /$b ) / ( 3435 / l( 10000 /$b ) - 298 )" | bc -l) $c $d; done < file_1k > /dev/null
real    0m39.066s
user    0m7.433s
sys     0m24.458s

$ time awk 'BEGIN{FS=OFS=",";OFMT="%.20f"} {d=log(10000/$2); print $1, 1023630 / d / (3435/d - 298), $3, $4}' file_1k > /dev/null
real    0m0.060s
user    0m0.031s
sys     0m0.031s

Upvotes: 1

pacholik
pacholik

Reputation: 8972

Your $2 is probably empty (or of some invalid value).

Also natural logarithm in bc is l, not ln.

And finally, in your awk example, the code is in apostrophes, so $2 will not be evaluated at all.

Upvotes: 2

Related Questions