2

I have two functions for GNU bc in a Bash script.

BC_CEIL="define ceil(x) { if (x>0) { if (x%1>0) return x+(1-(x%1)) else return x } else return -1*floor(-1*x) }\n"
BC_FLOOR="define floor(x) { if (x>0) return x-(x%1) else return -1*ceil(-1*x) }\n"
echo -e "scale=2"$BC_CEIL$BC_FLOOR"ceil(2.5)" | bc

Both functions work fine in interactive bc. bc does not seem to allow multiple functions on one line separated by ; though, so I have to echo -n | bc with newlines at the end of each function. The above output is 2.5, not the expected 3.0 that I get if I type it into bc -i myself. It seems that bash calls bc for each line of echo output, rather than echo'ing it all to a single instance. Is there any workaround for this?

Gordon
  • 1,844
  • 4
  • 17
  • 32

2 Answers2

2

The scale needs to be zero for x%1 to work. You should normally only have one return from a function.

define ceil(x) { auto savescale; savescale = scale; scale = 0; if (x>0) { if (x%1>0) result = x+(1-(x%1)) else result = x } else result = -1*floor(-1*x);  scale = savescale; return result }
define floor(x) { auto savescale; savescale = scale; scale = 0; if (x>0) result = x-(x%1) else result = -1*ceil(-1*x);  scale = savescale; return result }

This needs a newline after the scale statement:

echo -e "scale=2\n"$BC_CEIL$BC_FLOOR"ceil(2.5)" | bc
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • The missing \n after scale was a typo after editing the copy-pasted code. I find different return statements in if/else blocks easier to read than a variable written everywhere and returned once, but in this case - since scale must be reset - a single return makes sense. – Gordon Apr 30 '10 at 22:45
  • 1
    @Gordon: Very nice. It doesn't make much sense to me that `bc` wouldn't have an int() built in or in its `-l` library. (Or floor/ceiling for that matter.) – Dennis Williamson May 01 '10 at 00:24
2

I believe 1. is incorrect. The if() comparison needs to be X >= 0 .

I find this works

define ceil(x) {                         
    if (x >= 0) { if (x%1>0) return x+(1-(x%1)) else return x } 
    else return -1*floor(-1*x)               
}
define floor(x) {                        
    if (x >= 0) return x-(x%1)               
    else return -1*ceil(-1*x)                
}
Emil
  • 7,220
  • 17
  • 76
  • 135