100 Languages Speedrun: Episode 38: BC
Tags: bc, unix
Published: 2021-12-28 19:03:25

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` prints `a` followed by a newline
* `print(a)` also prints `a` - 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 of `print 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](https://dev.to/taw/100-languages-speedrun-episode-19-julia-26ak).

### Code

[All code examples for the series will be in this repository](https://github.com/taw/100-languages-speedrun).

[Code for the BC episode is available here](https://github.com/taw/100-languages-speedrun/tree/master/episode-38-bc).