I like covering languages you already have installed, but don't know about it. So today's episode is about BC - arbitrary precision calculator language.
Its main selling point is in the name - arbitrary precision. Its main downside is also in the name - calculator language - as it's extremely limited.
Using bc
bc
expects a file, but we can use it in a few ways. You can run it from shell (-q
is quiet mode, otherwise it prints annoying 4 line banner if used this way):
$ bc -q
2^300
20370359763344860862684456884093781610514683936659362506361404493543\
81299763336706183397376
quit
With 2^300
and quit
being input. As you can see the output is being automatically formatted to not exceed 70 columns.
If you want to just pass some code on the command line, there's no equivalent to -e "code"
most other Unix languages have. You need to echo
the code and pipe it into bc
:
$ echo '2^100' | bc
1267650600228229401496703205376
Most shells nowadays have a shortcut for this kind of echo
. It's up to you if it's more readable:
$ bc <<< '2^100'
1267650600228229401496703205376
You can also use bc
from a script, but it needs both -q
(to prevent printing the stupid banner), and quit
command at the end (otherwise it will continue expecting your input):
#!/usr/bin/bc -q
2^100
quit
This is actually intentional feature, as you can define some functions and whatnot in the file, and then do calculations on them. For example with this file:
#!/usr/bin/bc -q
a = 100
b = 200
We can do this:
$ ./interactive.bc
a+b
300
quit
Powers of 2
The looping is done with while
. Any calculation that doesn't get assigned to some variable is interpretted as a print. So this a
line means to print a
:
#!/usr/bin/bc -q
a = 1
i = 1
while (i <= 32) {
a
a = a*2
i = i+1
}
quit
It works just as expected:
$ ./powers.bc
1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
2147483648
Fibonacci
The Fibonacci sequence is just as you'd expect, the interesting part is printing it:
#!/usr/bin/bc -q
a = 1
b = 1
i = 1
while (i <= 100) {
if (i >= 90) {
"fib("
print(i)
") = "
print(a)
"
"
}
c = a+b
a = b
b = c
i = i+1
}
quit
Which generates:
./fib.bc
fib(90) = 2880067194370816120
fib(91) = 4660046610375530309
fib(92) = 7540113804746346429
fib(93) = 12200160415121876738
fib(94) = 19740274219868223167
fib(95) = 31940434634990099905
fib(96) = 51680708854858323072
fib(97) = 83621143489848422977
fib(98) = 135301852344706746049
fib(99) = 218922995834555169026
fib(100) = 354224848179261915075
Step by step:
- any calculation without assignment like
a
printsa
followed by a newline -
print(a)
also printsa
- but without a newline -
"string"
prints a string - if you want to print a newline alone, there's no
"\n"
- you need to start"
on one line, and end on the next. - in this case we could just do
a
instead ofprint a
followed by print newline trick, but I wanted to show the full range of printing options.
FizzBuzz
The first problem we run into is that bc
has if
but it doesn't have else, so we need to either return
from the function or do the second if
with reversed condition.
The second problem is that if we call fizzbuzz(i)
, bc
will try to print the result of the function, which is 0
, and so we need to assign it to something. bc
does not support _
as variable name, so the convention of _ = something()
so common in many other languages for throwing out results is not really possible:
#!/usr/bin/bc -q
define fizzbuzz(n) {
if (n % 15 == 0) {
"FizzBuzz
"
return
}
if (n % 5 == 0) {
"Buzz
"
return
}
if (n % 3 == 0) {
"Fizz
"
return
}
n
}
i = 1
while (i <= 100) {
unused = fizzbuzz(i)
i = i + 1
}
quit
Knowing these limitations, we can rewrite it in a nicer way:
#!/usr/bin/bc -q
i = 1
while (i <= 100) {
t = i % 3
v = i % 5
if (t == 0) { "Fizz" }
if (v == 0) { "Buzz" }
if (t != 0 && v != 0) { print(i) }
"
"
i = i + 1
}
quit
Pythagorean theorem
Just about every language supports arbitrary precision integers, so none of that has been impressive. Let's try something that is a bit less common - arbitrary precision decimals.
By default bc
uses scale = 0
, that is everything is an integer. We need to set scale
to however many decimal places we want:
#!/usr/bin/bc -q
scale = 60
a = read()
b = read()
sqrt(a^2 + b^2)
quit
Which prints the answer to 60 decimal places:
$ ./pythagoras.bc
69
420
425.630121114565856802783307310908277784184864514438295059161980
Should you use BC?
No.
It had a niche back in the olden days when the alternatives were C and Shell. Nowadays most languages have arbitrary sized integers - either by default like Ruby or Python, or with easy one letter suffix like JavaScript's 69n
, so there's really no point whatsoever in learning bc
if you just need big integers.
With arbitrary precision decimals, it's arguably somewhat useful. All languages have some kind of arbitrary precission decimal libraries, but they're often a bit awkward to use.
Still, I don't think this makes learning bc
worth it - for almost every use case, unlimited integers and regular builtin floating point numbers are sufficient, and if you find yourself needing arbitrary precission decimals or arbitrary precission float a lot, you should probably learn proper mathematical language like Julia.
Code
All code examples for the series will be in this repository.
Top comments (0)