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 # handle help options 42 case "$1" in 43 -h|--h|-help|--help) 44 awk '/^# +ca /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 45 exit 0 46 ;; 47 esac 48 49 if [ $# -eq 0 ]; then 50 awk '/^# +ca /, /^$/ { gsub(/^# ?/, ""); print }' "$0" 51 exit 0 52 fi 53 54 # default max-accuracy decimals to use for calculations 55 scale=25 56 57 # ensure each output is all on 1 line, define several funcs and values, then 58 # inject the expressions given as this script's arguments, transforming them 59 # according to the rules described above 60 for arg in "$@"; do 61 # printf "\e[7m%s\e[0m\n" "${arg}" > /dev/stderr 62 [ $# -ge 2 ] && printf "\e[7m%s\e[0m\n" "${arg}" > /dev/stderr 63 64 BC_LINE_LENGTH=0 bc -l << ENDOFSCRIPT 65 scale = ${scale}; 66 67 femto = 0.000000000000001; 68 pico = 0.000000000001; 69 nano = 0.000000001; 70 micro = 0.000001; 71 milli = 0.001; 72 73 kilo = 1000; 74 mega = 1000 * kilo; 75 giga = 1000 * mega; 76 tera = 1000 * giga; 77 peta = 1000 * tera; 78 exa = 1000 * peta; 79 zetta = 1000 * exa; 80 81 binkilo = 1024; 82 binmega = 1024 * binkilo; 83 bingiga = 1024 * binmega; 84 bintera = 1024 * bingiga; 85 binpeta = 1024 * bintera; 86 binexa = 1024 * binpeta; 87 binzetta = 1024 * binexa; 88 89 kb = 1024; 90 mb = 1024 * kb; 91 gb = 1024 * mb; 92 tb = 1024 * gb; 93 pb = 1024 * tb; 94 eb = 1024 * pb; 95 zb = 1024 * eb; 96 97 kib = 1024; 98 mib = 1024 * kib; 99 gib = 1024 * mib; 100 tib = 1024 * gib; 101 pib = 1024 * tib; 102 zib = 1024 * pib; 103 104 mol = 602214076000000000000000; 105 mole = 602214076000000000000000; 106 107 cup2l = 0.23658824; 108 floz2l = 0.0295735295625; 109 floz2ml = 29.5735295625; 110 ft2m = 0.3048; 111 gal2l = 3.785411784; 112 in2cm = 2.54; 113 lb2kg = 0.45359237; 114 mi2km = 1.609344; 115 mpg2kpl = 0.425143707; 116 nmi2km = 1.852; 117 oz2g = 28.349523125 118 psi2pa = 6894.757293168; 119 ton2kg = 907.18474; 120 yd2m = 0.9144; 121 122 ga2l = gal2l; 123 nm2km = nmi2km; 124 tn2kg = ton2kg; 125 126 hour = 3600; 127 day = 24 * hour; 128 week = 7 * day; 129 130 hr = hour; 131 wk = week; 132 133 define ftin(f, i) { 134 return (0.3048 * f + 0.0254 * i); 135 } 136 137 define lboz(l, o) { 138 return (0.45359237 * l + 0.028349523 * o); 139 } 140 141 define eu() { 142 return (e(1)); 143 } 144 145 define euler() { 146 return (e(1)); 147 } 148 149 define pi() { 150 return (4*a(1)); 151 } 152 153 define tau() { 154 return (8*a(1)); 155 } 156 157 define deg(x) { 158 return (180 * x / pi()); 159 } 160 161 define rad(x) { 162 return (pi() * x / 180); 163 } 164 165 define abs(x) { 166 if (x >= 0) return (x); 167 return (-x); 168 } 169 170 define exp(x) { 171 return (e(x)); 172 } 173 174 define j0(x) { 175 return (j(0, x)); 176 } 177 178 define j1(x) { 179 return (j(1, x)); 180 } 181 182 define ln(x) { 183 return (l(x)); 184 } 185 186 define log(x) { 187 return (l(x)); 188 } 189 190 # define log2(x) { 191 # return (l(x) / l(2)); 192 # } 193 194 define log2(x) { 195 auto r, n; 196 if (x <= 0) return (l(x) / l(2)); 197 198 r = 0; 199 for (n = x; n > 1; n /= 2) r += 1; 200 201 if (n == 1) return (r); 202 return (l(x) / l(2)); 203 } 204 205 # define log10(x) { 206 # return (l(x) / l(10)); 207 # } 208 209 define log10(x) { 210 auto r, n; 211 if (x <= 0) return (l(x) / l(10)); 212 213 r = 0; 214 for (n = x; n > 1; n /= 10) r += 1; 215 216 if (n == 1) return (r); 217 return (l(x) / l(10)); 218 } 219 220 define sin(x) { 221 return (s(x)); 222 } 223 224 define cos(x) { 225 return (c(x)); 226 } 227 228 define tan(x) { 229 return (s(x) / c(x)); 230 } 231 232 define cot(x) { 233 return (c(x) / s(x)); 234 } 235 236 define atan(x) { 237 return (a(x)); 238 } 239 240 define sinh(x) { 241 return ((e(x) - e(-x)) / 2); 242 } 243 244 define cosh(x) { 245 return ((e(x) + e(-x)) / 2); 246 } 247 248 define tanh(x) { 249 return ((e(x) - e(-x)) / (e(x) + e(-x))); 250 } 251 252 define coth(x) { 253 return ((e(x) + e(-x)) / (e(x) - e(-x))); 254 } 255 256 define hypot(x, y) { 257 return (sqrt(x*x + y*y)); 258 } 259 260 define sinc(x) { 261 if (x == 0) return (1); 262 return (s(x) / x); 263 } 264 265 define min(x, y) { 266 if (x <= y) return (x); 267 return (y); 268 } 269 270 define max(x, y) { 271 if (x >= y) return (x); 272 return (y); 273 } 274 275 define mod(x, y) { 276 auto s, m; 277 s = scale; 278 scale = 0; 279 m = x % y; 280 scale = s; 281 return (m); 282 } 283 284 define mod1(x) { 285 return (mod(x, 1)); 286 } 287 288 define modf(x) { 289 return (mod(x, 1)); 290 } 291 292 define round0(x) { 293 auto i; 294 i = x - mod(x, 1); 295 if (x - i >= 0.5) { 296 return (i + 1); 297 } 298 return (i); 299 } 300 301 define round(x, d) { 302 auto k; 303 k = 10^d; 304 return (round0(x * k) / k); 305 } 306 307 define r(x, d) { 308 return (round(x, d)); 309 } 310 311 define r0(x) { 312 return (round0(x)); 313 } 314 315 define fac(x) { 316 auto f, i; 317 if (x < 0) return (0); 318 f = 1; 319 for (i = x; i >= 2; i--) { f *= i; } 320 return (f); 321 } 322 323 define f(x) { 324 return (fac(x)); 325 } 326 327 define fact(x) { 328 return (fac(x)); 329 } 330 331 define factorial(x) { 332 return (fac(x)); 333 } 334 335 define per(n, k) { 336 auto p, i; 337 if (n < k) return (0); 338 p = 1; 339 for (i = n; i >= n - k + 1; i--) { p *= i; } 340 return (p); 341 } 342 343 define p(n, k) { 344 return (per(n, k)); 345 } 346 347 define perm(n, k) { 348 return (per(n, k)); 349 } 350 351 define com(n, k) { 352 if (n < k) return (0); 353 return (per(n, k) / fac(k)); 354 } 355 356 define comb(n, k) { 357 return (com(n, k)); 358 } 359 360 define gcd(x, y) { 361 return (x * y / lcm(x, y)); 362 } 363 364 define lcm(x, y) { 365 auto a, b, z; 366 367 /* the LCM is defined only for positive integers */ 368 # if (mod(x, 1) != 0 || x < 1 || mod(y, 1) != 0 || y < 1) { return 0; } 369 # if (mod(x, 1) != 0) return (0); 370 if (x < 1) return (0); 371 # if (mod(y, 1) != 0) return (0); 372 if (y < 1) return (0); 373 374 a = min(x, y); 375 b = max(x, y); 376 377 z = b; 378 while (mod(z, a) != 0) { z += b; } 379 return (z); 380 } 381 382 define sgn(x) { 383 if (x > 0) return (1); 384 if (x < 0) return (-1); 385 return (0); 386 } 387 388 define sign(x) { 389 return (sgn(x)); 390 } 391 392 define logistic(x) { 393 return (1 / (1 + e(-x))); 394 } 395 396 $(echo "${arg}" | sed 's-^+--g; s-_--g; s-\*\*-^-g; s-\[-(-g; s-\]-)-g') 397 ENDOFSCRIPT 398 399 done | 400 # ensure the result shows at least a zero before the decimal dot, then 401 # rid the result of trailing zero decimals and/or trailing decimal dots 402 sed -E 's-^\.-0.-; s/^-\./-0./; s-(\.[0-9]+[1-9]+)0+$-\1-; s-\.0*$--'