File: ca.sh 1 #!/bin/sh 2 3 # The MIT License (MIT) 4 # 5 # Copyright © 2020-2025 pacman64 6 # 7 # Permission is hereby granted, free of charge, to any person obtaining a copy 8 # of this software and associated documentation files (the “Software”), to deal 9 # in the Software without restriction, including without limitation the rights 10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 # copies of the Software, and to permit persons to whom the Software is 12 # furnished to do so, subject to the following conditions: 13 # 14 # The above copyright notice and this permission notice shall be included in 15 # all copies or substantial portions of the Software. 16 # 17 # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 # SOFTWARE. 24 25 26 # ca [expressions...] 27 # 28 # 29 # CAlculator is an easier-to-use way of running `bc` (basic calculator) where 30 # 31 # - you can calculate multiple different things in one run 32 # - you give the expressions as arguments, while `bc` reads it from stdin 33 # - you don't need quoting when avoiding parentheses and spaces 34 # - you can use either ** or ^ to raise powers 35 # - you can use [ and ] or ( and ) interchangeably 36 # - the number of max-accuracy decimals is 25 by default 37 # - automatically includes the extended bc math library via option -l 38 # - there are several extra predefined values and functions 39 40 41 case "$1" in 42 -h|--h|-help|--help) 43 awk '/^# +ca /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 44 exit 0 45 ;; 46 esac 47 48 if [ $# -eq 0 ]; then 49 awk '/^# +ca /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 50 exit 0 51 fi 52 53 # default max-accuracy decimals to use for calculations 54 scale=25 55 56 # ensure each output is all on 1 line, define several funcs and values, then 57 # inject the expressions given as this script's arguments, transforming them 58 # according to the rules described above 59 for arg in "$@"; do 60 # printf "\e[7m%s\e[0m\n" "${arg}" > /dev/stderr 61 [ $# -ge 2 ] && printf "\e[7m%s\e[0m\n" "${arg}" > /dev/stderr 62 63 BC_LINE_LENGTH=0 bc -l << ENDOFSCRIPT 64 scale = ${scale}; 65 66 femto = 0.000000000000001; 67 pico = 0.000000000001; 68 nano = 0.000000001; 69 micro = 0.000001; 70 milli = 0.001; 71 72 kilo = 1000; 73 mega = 1000 * kilo; 74 giga = 1000 * mega; 75 tera = 1000 * giga; 76 peta = 1000 * tera; 77 exa = 1000 * peta; 78 zetta = 1000 * exa; 79 80 binkilo = 1024; 81 binmega = 1024 * binkilo; 82 bingiga = 1024 * binmega; 83 bintera = 1024 * bingiga; 84 binpeta = 1024 * bintera; 85 binexa = 1024 * binpeta; 86 binzetta = 1024 * binexa; 87 88 kb = 1024; 89 mb = 1024 * kb; 90 gb = 1024 * mb; 91 tb = 1024 * gb; 92 pb = 1024 * tb; 93 eb = 1024 * pb; 94 zb = 1024 * eb; 95 96 kib = 1024; 97 mib = 1024 * kib; 98 gib = 1024 * mib; 99 tib = 1024 * gib; 100 pib = 1024 * tib; 101 zib = 1024 * pib; 102 103 mol = 602214076000000000000000; 104 mole = 602214076000000000000000; 105 106 cup = 0.23658824; 107 cup2l = 0.23658824; 108 floz2l = 0.0295735295625; 109 floz2ml = 29.5735295625; 110 ft = 0.3048; 111 ft2m = 0.3048; 112 gal = 3.785411784; 113 gal2l = 3.785411784; 114 in = 2.54; 115 in2cm = 2.54; 116 lb = 0.45359237; 117 lb2kg = 0.45359237; 118 mi = 1.609344; 119 mi2km = 1.609344; 120 mpg = 0.425143707; 121 mpg2kpl = 0.425143707; 122 nm = 1.852; 123 nm2km = 1.852; 124 nmi = 1.852; 125 nmi2km = 1.852; 126 oz2g = 28.349523125 127 psi2pa = 6894.757293168; 128 ton = 907.18474; 129 ton2kg = 907.18474; 130 yd = 0.9144; 131 yd2m = 0.9144; 132 133 ga2l = gal2l; 134 nm2km = nmi2km; 135 tn2kg = ton2kg; 136 137 million = 1000000 138 billion = 1000 * million 139 trillion = 1000 * billion 140 141 hour = 3600; 142 day = 24 * hour; 143 week = 7 * day; 144 145 hr = hour; 146 wk = week; 147 148 define ftin(f, i) { 149 return (0.3048 * f + 0.0254 * i); 150 } 151 152 define lboz(l, o) { 153 return (0.45359237 * l + 0.028349523 * o); 154 } 155 156 define eu() { 157 return (e(1)); 158 } 159 160 define euler() { 161 return (e(1)); 162 } 163 164 define pi() { 165 return (4 * a(1)); 166 } 167 168 define tau() { 169 return (8 * a(1)); 170 } 171 172 define deg(x) { 173 return (180 * x / pi()); 174 } 175 176 define rad(x) { 177 return (pi() * x / 180); 178 } 179 180 define degrees(x) { 181 return (deg(x)); 182 } 183 184 define radians(x) { 185 return (rad(x)); 186 } 187 188 define abs(x) { 189 if (x >= 0) return (x); 190 return (-x); 191 } 192 193 define exp(x) { 194 return (e(x)); 195 } 196 197 define j0(x) { 198 return (j(0, x)); 199 } 200 201 define j1(x) { 202 return (j(1, x)); 203 } 204 205 define ln(x) { 206 return (l(x)); 207 } 208 209 define log(x) { 210 return (l(x)); 211 } 212 213 /* 214 define log2(x) { 215 return (l(x) / l(2)); 216 } 217 */ 218 219 define log2(x) { 220 auto r, n; 221 if (x <= 0) return (l(x) / l(2)); 222 223 r = 0; 224 for (n = x; n > 1; n /= 2) r += 1; 225 226 if (n == 1) return (r); 227 return (l(x) / l(2)); 228 } 229 230 /* 231 define log10(x) { 232 return (l(x) / l(10)); 233 } 234 */ 235 236 define log10(x) { 237 auto r, n; 238 if (x <= 0) return (l(x) / l(10)); 239 240 r = 0; 241 for (n = x; n > 1; n /= 10) r += 1; 242 243 if (n == 1) return (r); 244 return (l(x) / l(10)); 245 } 246 247 define sin(x) { 248 return (s(x)); 249 } 250 251 define cos(x) { 252 return (c(x)); 253 } 254 255 define tan(x) { 256 return (s(x) / c(x)); 257 } 258 259 define cot(x) { 260 return (c(x) / s(x)); 261 } 262 263 define atan(x) { 264 return (a(x)); 265 } 266 267 define sinh(x) { 268 return ((e(x) - e(-x)) / 2); 269 } 270 271 define cosh(x) { 272 return ((e(x) + e(-x)) / 2); 273 } 274 275 define tanh(x) { 276 return ((e(x) - e(-x)) / (e(x) + e(-x))); 277 } 278 279 define coth(x) { 280 return ((e(x) + e(-x)) / (e(x) - e(-x))); 281 } 282 283 define hypot(x, y) { 284 return (sqrt(x*x + y*y)); 285 } 286 287 define sinc(x) { 288 if (x == 0) return (1); 289 return (s(x) / x); 290 } 291 292 define min(x, y) { 293 if (x <= y) return (x); 294 return (y); 295 } 296 297 define max(x, y) { 298 if (x >= y) return (x); 299 return (y); 300 } 301 302 define mod(x, y) { 303 auto s, m; 304 s = scale; 305 scale = 0; 306 m = x % y; 307 scale = s; 308 return (m); 309 } 310 311 define mod1(x) { 312 return (mod(x, 1)); 313 } 314 315 define modf(x) { 316 return (mod(x, 1)); 317 } 318 319 define mix(x, y, k) { 320 return (x * (1 - k) + y * k); 321 } 322 323 define round0(x) { 324 auto i; 325 i = x - mod(x, 1); 326 if (x - i >= 0.5) { 327 return (i + 1); 328 } 329 return (i); 330 } 331 332 define round(x, d) { 333 auto k; 334 k = 10 ^ d; 335 return (round0(x * k) / k); 336 } 337 338 define r(x, d) { 339 return (round(x, d)); 340 } 341 342 define r0(x) { 343 return (round0(x)); 344 } 345 346 define epa(x) { 347 return (epanechnikov(x)); 348 } 349 350 define epanechnikov(x) { 351 if ((x < -1) || (x > 1)) return (0); 352 return (3 / 4 * (1 - (x * x))); 353 } 354 355 define gauss(x) { 356 return (gaussian(x)); 357 } 358 359 define gaussian(x) { 360 return (e(-(x * x))); 361 } 362 363 define tricube(x) { 364 auto a, b, c, d; 365 if ((x < -1) || (x > 1)) return (0); 366 if (x >= 0) a = x else a = -x; 367 b = a * a * a; 368 c = 1 - b; 369 d = c * c * c; 370 return (70 / 81 * d); 371 } 372 373 define fac(x) { 374 auto f, i; 375 if (x < 0) return (0); 376 f = 1; 377 for (i = x; i >= 2; i--) f *= i; 378 return (f); 379 } 380 381 define f(x) { 382 return (fac(x)); 383 } 384 385 define fact(x) { 386 return (fac(x)); 387 } 388 389 define factorial(x) { 390 return (fac(x)); 391 } 392 393 define per(n, k) { 394 auto p, i; 395 if (n < k) return (0); 396 p = 1; 397 for (i = n; i >= n - k + 1; i--) p *= i; 398 return (p); 399 } 400 401 define p(n, k) { 402 return (per(n, k)); 403 } 404 405 define perm(n, k) { 406 return (per(n, k)); 407 } 408 409 define permut(n, k) { 410 return (per(n, k)); 411 } 412 413 define permutations(n, k) { 414 return (per(n, k)); 415 } 416 417 /* the name "c" is already used for the cosine function in "bc" */ 418 419 define choose(n, k) { 420 return (com(n, k)); 421 } 422 423 define com(n, k) { 424 if (n < k) return (0); 425 return (per(n, k) / fac(k)); 426 } 427 428 define comb(n, k) { 429 return (com(n, k)); 430 } 431 432 define combin(n, k) { 433 return (com(n, k)); 434 } 435 436 define combinations(n, k) { 437 return (com(n, k)); 438 } 439 440 define gcd(x, y) { 441 return (x * y / lcm(x, y)); 442 } 443 444 define lcm(x, y) { 445 auto a, b, z; 446 447 /* the LCM is defined only for positive integers */ 448 /* if (mod(x, 1) != 0 || x < 1 || mod(y, 1) != 0 || y < 1) return (0); */ 449 /* if (mod(x, 1) != 0) return (0); */ 450 if (x < 1) return (0); 451 /* if (mod(y, 1) != 0) return (0); */ 452 if (y < 1) return (0); 453 454 a = min(x, y); 455 b = max(x, y); 456 457 z = b; 458 while (mod(z, a) != 0) { z += b; } 459 return (z); 460 } 461 462 define dbin(x, n, p) { 463 return (dbinom(x, n, p)); 464 } 465 466 define pbin(x, n, p) { 467 return (pbinom(x, n, p)); 468 } 469 470 define dbinom(x, n, p) { 471 return (com(n, x) * (p ^ x) * ((1 - p) ^ (n - x))); 472 } 473 474 /* pbinom inefficiently repeats calculations for now, which keeps it simple */ 475 define pbinom(x, n, p) { 476 auto k, t; 477 t = 0; 478 for (k = 0; k <= n; k++) t += dbinom(k, n, p); 479 return (t); 480 } 481 482 /* pbinomfast may be wrong, while the simpler pbinom seems correct */ 483 define pbinomfast(x, n, p) { 484 auto a, b, d, q, k, t; 485 if ((p < 0) || (p > 1)) return (0); 486 if (x < 0) return (0); 487 if (x >= n) return (1); 488 a = 1; 489 q = 1 - p; 490 b = b ^ n; 491 d = 1; 492 t = 0; 493 for (k = 0; k < x;) { 494 t += (per(n, k) / d) * a * b; 495 a *= p; 496 b /= q; 497 k++; 498 d *= k; 499 } 500 /* remember the last loop, where k == x */ 501 t += (per(n, k) / d) * a * b; 502 return (t); 503 } 504 505 define dexp(x, r) { 506 if (r < 0) return (0); 507 return (r * e(-r * x)); 508 } 509 510 define pexp(x, r) { 511 if (r < 0) return (0); 512 return (1 - e(-r * x)); 513 } 514 515 define dpois(x, l) { 516 return ((l ^ x) * e(-l) / fac(x)); 517 } 518 519 define ppois(x, l) { 520 auto t, d, i; 521 t = 1; 522 d = 1; 523 for (i = 1; i <= l; i++) { 524 d *= i; 525 t += (l ^ i) / d; 526 } 527 return (e(-l) * t); 528 } 529 530 define sgn(x) { 531 if (x > 0) return (1); 532 if (x < 0) return (-1); 533 return (0); 534 } 535 536 define sign(x) { 537 return (sgn(x)); 538 } 539 540 define logistic(x) { 541 return (1 / (1 + e(-x))); 542 } 543 544 $(echo "${arg}" | sed 's-^+--g; s-_--g; s-\*\*-^-g; s-\[-(-g; s-\]-)-g') 545 ENDOFSCRIPT 546 547 done | 548 # ensure the result shows at least a zero before the decimal dot, then 549 # rid the result of trailing zero decimals and/or trailing decimal dots 550 sed -E 's-^\.-0.-; s/^-\./-0./; s-(\.[0-9]*[1-9])0+$-\1-; s-\.0*$--'