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