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 cup2l = 0.23658824; 107 floz2l = 0.0295735295625; 108 floz2ml = 29.5735295625; 109 ft2m = 0.3048; 110 gal2l = 3.785411784; 111 in2cm = 2.54; 112 lb2kg = 0.45359237; 113 mi2km = 1.609344; 114 mpg2kpl = 0.425143707; 115 nmi2km = 1.852; 116 oz2g = 28.349523125 117 psi2pa = 6894.757293168; 118 ton2kg = 907.18474; 119 yd2m = 0.9144; 120 121 ga2l = gal2l; 122 nm2km = nmi2km; 123 tn2kg = ton2kg; 124 125 hour = 3600; 126 day = 24 * hour; 127 week = 7 * day; 128 129 hr = hour; 130 wk = week; 131 132 define ftin(f, i) { 133 return (0.3048 * f + 0.0254 * i); 134 } 135 136 define lboz(l, o) { 137 return (0.45359237 * l + 0.028349523 * o); 138 } 139 140 define eu() { 141 return (e(1)); 142 } 143 144 define euler() { 145 return (e(1)); 146 } 147 148 define pi() { 149 return (4*a(1)); 150 } 151 152 define tau() { 153 return (8*a(1)); 154 } 155 156 define deg(x) { 157 return (180 * x / pi()); 158 } 159 160 define rad(x) { 161 return (pi() * x / 180); 162 } 163 164 define abs(x) { 165 if (x >= 0) return (x); 166 return (-x); 167 } 168 169 define exp(x) { 170 return (e(x)); 171 } 172 173 define j0(x) { 174 return (j(0, x)); 175 } 176 177 define j1(x) { 178 return (j(1, x)); 179 } 180 181 define ln(x) { 182 return (l(x)); 183 } 184 185 define log(x) { 186 return (l(x)); 187 } 188 189 # define log2(x) { 190 # return (l(x) / l(2)); 191 # } 192 193 define log2(x) { 194 auto r, n; 195 if (x <= 0) return (l(x) / l(2)); 196 197 r = 0; 198 for (n = x; n > 1; n /= 2) r += 1; 199 200 if (n == 1) return (r); 201 return (l(x) / l(2)); 202 } 203 204 # define log10(x) { 205 # return (l(x) / l(10)); 206 # } 207 208 define log10(x) { 209 auto r, n; 210 if (x <= 0) return (l(x) / l(10)); 211 212 r = 0; 213 for (n = x; n > 1; n /= 10) r += 1; 214 215 if (n == 1) return (r); 216 return (l(x) / l(10)); 217 } 218 219 define sin(x) { 220 return (s(x)); 221 } 222 223 define cos(x) { 224 return (c(x)); 225 } 226 227 define tan(x) { 228 return (s(x) / c(x)); 229 } 230 231 define cot(x) { 232 return (c(x) / s(x)); 233 } 234 235 define atan(x) { 236 return (a(x)); 237 } 238 239 define sinh(x) { 240 return ((e(x) - e(-x)) / 2); 241 } 242 243 define cosh(x) { 244 return ((e(x) + e(-x)) / 2); 245 } 246 247 define tanh(x) { 248 return ((e(x) - e(-x)) / (e(x) + e(-x))); 249 } 250 251 define coth(x) { 252 return ((e(x) + e(-x)) / (e(x) - e(-x))); 253 } 254 255 define hypot(x, y) { 256 return (sqrt(x*x + y*y)); 257 } 258 259 define sinc(x) { 260 if (x == 0) return (1); 261 return (s(x) / x); 262 } 263 264 define min(x, y) { 265 if (x <= y) return (x); 266 return (y); 267 } 268 269 define max(x, y) { 270 if (x >= y) return (x); 271 return (y); 272 } 273 274 define mod(x, y) { 275 auto s, m; 276 s = scale; 277 scale = 0; 278 m = x % y; 279 scale = s; 280 return (m); 281 } 282 283 define mod1(x) { 284 return (mod(x, 1)); 285 } 286 287 define modf(x) { 288 return (mod(x, 1)); 289 } 290 291 define round0(x) { 292 auto i; 293 i = x - mod(x, 1); 294 if (x - i >= 0.5) { 295 return (i + 1); 296 } 297 return (i); 298 } 299 300 define round(x, d) { 301 auto k; 302 k = 10^d; 303 return (round0(x * k) / k); 304 } 305 306 define r(x, d) { 307 return (round(x, d)); 308 } 309 310 define r0(x) { 311 return (round0(x)); 312 } 313 314 define fac(x) { 315 auto f, i; 316 if (x < 0) return (0); 317 f = 1; 318 for (i = x; i >= 2; i--) { f *= i; } 319 return (f); 320 } 321 322 define f(x) { 323 return (fac(x)); 324 } 325 326 define fact(x) { 327 return (fac(x)); 328 } 329 330 define factorial(x) { 331 return (fac(x)); 332 } 333 334 define per(n, k) { 335 auto p, i; 336 if (n < k) return (0); 337 p = 1; 338 for (i = n; i >= n - k + 1; i--) { p *= i; } 339 return (p); 340 } 341 342 define p(n, k) { 343 return (per(n, k)); 344 } 345 346 define perm(n, k) { 347 return (per(n, k)); 348 } 349 350 define com(n, k) { 351 if (n < k) return (0); 352 return (per(n, k) / fac(k)); 353 } 354 355 define comb(n, k) { 356 return (com(n, k)); 357 } 358 359 define gcd(x, y) { 360 return (x * y / lcm(x, y)); 361 } 362 363 define lcm(x, y) { 364 auto a, b, z; 365 366 /* the LCM is defined only for positive integers */ 367 # if (mod(x, 1) != 0 || x < 1 || mod(y, 1) != 0 || y < 1) { return 0; } 368 # if (mod(x, 1) != 0) return (0); 369 if (x < 1) return (0); 370 # if (mod(y, 1) != 0) return (0); 371 if (y < 1) return (0); 372 373 a = min(x, y); 374 b = max(x, y); 375 376 z = b; 377 while (mod(z, a) != 0) { z += b; } 378 return (z); 379 } 380 381 define sgn(x) { 382 if (x > 0) return (1); 383 if (x < 0) return (-1); 384 return (0); 385 } 386 387 define sign(x) { 388 return (sgn(x)); 389 } 390 391 define logistic(x) { 392 return (1 / (1 + e(-x))); 393 } 394 395 $(echo "${arg}" | sed 's-^+--g; s-_--g; s-\*\*-^-g; s-\[-(-g; s-\]-)-g') 396 ENDOFSCRIPT 397 398 done | 399 # ensure the result shows at least a zero before the decimal dot, then 400 # rid the result of trailing zero decimals and/or trailing decimal dots 401 sed -E 's-^\.-0.-; s/^-\./-0./; s-(\.[0-9]+[1-9]+)0+$-\1-; s-\.0*$--'