4

I've found tons and tons of information about rounding a float to a specific number of decimal places by using 'scale' with BC and '%.xf' with printf, but if I'm working with numbers that don't always have the same format like I've shown below, is there a way to round it to the first decimal place that isn't a zero?

For example, say I have a list of numbers like this:

0.0008234535225
0.00547889294
0.000003243322

Is there a way for me to convert them to something like this?:

0.0008
0.005
0.000003

Every Google result I've come across is talking about rounding to a specific number of digits instead of to the first significant number and I'm not having much success in filtering them from the search results, so it's making figuring out this problem entirely on my own a bit difficult.

Could someone please point me in the right direction?

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
Thorium
  • 191
  • 1
  • 14
  • 2
    What should be the output for `0.000003943322`? – higuaro May 08 '15 at 03:22
  • and what do you mean by `possible`? I'm guessing that you'd have to examine each value separately, and set the the x in `%xf` after "counting" the leading 0s. An interesting problem, but I don't see a bulk solution. Good luck! – shellter May 08 '15 at 03:28
  • @higuaro the output would be '0.000003', but if you know of a solution that would round it up to '0.000004', that would be fine too. Also, I meant possible as in, does BASH/bc/printf actually have the capability to do this or will I have to use some other tool? – Thorium May 08 '15 at 03:41

3 Answers3

4

The following will truncate your numbers to the first non 0 digit:

grep -o "0.0*." <<< "$NUMBER"

For example:

grep -o "0.0*." <<< "0.000003243322"

Prints:

0.000003
higuaro
  • 15,730
  • 4
  • 36
  • 43
  • Consider these inputs: `'0.1.000'` and `'0..1'`. – kojiro May 08 '15 at 03:59
  • 3
    The question doesn't specify anything about handling invalid format numbers. In fact, the OP make it clear that he is dealing with numbers of the form `0.000...[non-zero-digit][digit]` – higuaro May 08 '15 at 04:01
  • OK. That said, answers on SO can be improved by considering the case for other visitors besides the OP looking for _similar_ solutions. – kojiro May 08 '15 at 04:06
  • 2
    "What should be the output for `0.000003943322`" if the desired output is `0.000004`, this could work: `sed -r 's|(0\.0*)(.)(.*)|t=\2/\1\2\;scale=l(t)/l(10)\;(&*t+0.5)/t|' <<< 0.000003943322 | bc`. I know, OP wants to truncate. Here is the round-off solution, just for reference. – anishsane May 08 '15 at 04:59
  • @anishsane i get `Runtime error (func=(main), adr=13): Function l not defined.` ? –  May 08 '15 at 07:52
  • use `bc -l` instead of `bc`. I forgot that I had `alias bc="bc -l"`... :D – anishsane May 08 '15 at 08:03
1

If you're willing to process these values as strings, you can use a few parameter expansions:

$ cat x
0.0008234535225
0.00547889294
0.000003243322
0.00012034

$ for line in $(<x); do
> exp="${line%%[^0.]*}" mant="${line#$exp}"
> echo "${exp}${mant:0:1}"
> done
0.0008
0.005
0.000003
0.0001
kojiro
  • 74,557
  • 19
  • 143
  • 201
0

It could be done directly in the shell without any external tool:

$ n=0.0008234535225; echo "${n%"${n#*[^0.,+-]}"}"
0.0008

Or defined as a function:

$ f(){ for i do echo "${i%"${i#*[^0.,+-]}"}"; done; }
$ f 0.0008234535225 0.00547889294 0.000003243322
0.0008
0.005
0.000003

It also process negative numbers (or with positive sign or with germany ,):

$ f  -0.0008234535225 -0.00547889294 -0.000003243322
-0.0008
-0.005
-0.000003