#!/bin/bash
# Tämä on skriptiajurin skripti ~/OMATSKRIPTIT/FUNKTIOKIRJASTO/matemaattiset_funktiot, mutta siä voi käyttää yksinäänkin. petteriIII 27.3.2019 http://forum.ubuntu-fi.org/index.php?topic=47408.msg364003#top. 

# Toiminta on yksinkertaitettuna seuraava: niin kauan kuin laskussa on sulkuja tehdään korkeimman tason sulun sisällöstä rekursiivinen kutsu. Etsitään tässä uudessa laskussa olevat funktiot ja niiden argumentit, ratkaistaan funktiot ja korvataan funktiot argumentteineen saadulla arvolla. Kun funktioita ei ole enempää niin lähetetään peruslaskutoimituksista muodostuva loppu bc:lle joka antaa sille numeroarvon, palataan rekursiosta ja korvataan alkuperäisessä laskussa sulku siitä saadulla arvolla. Uusia sulkuja etsitään ja ratkaistaan mutta rekursiota ei enää tehdä kun sulkuja ei enää ole. Sitten etsitään jäljelle jääneestä laskusta siinä olevat funktiot argumentteineen ja korvataan funktiot argumentteineen saadulla arvolla. Kun funktioitakaan ei enää ole niin lähetetään lasku jossa on jäljellä vain peruslaskutoimituksia bc:n ratkaistavaksi. 

# Kohdattaessa lasku aina ei ole ilmanmuuta selvää onko kysymys peruslaskutoimituksesta vai funktiosta. Esimerkiksi bc:n kannalta kokonaislukupotenssi on nopea ja tarkka peruslaskutoimitus mutta desimaalipotenssi on funktio joka on hieman hitaampi ja virheellisempi. Joten tämä skripti valitsee tehdäänkö peruslaskutoimitus vai mennäänkö funktioon joten aina toimitaan parhaalla mahdollisella tavalla.

# Skriptin rakenne ei ole seväpiirteinen eikä senvuoksi kommentointiakaan ole paljoa. Vaan kannattaa ottaa kaikki vain esimerkkinä siitä mihin BASH kykenee. Toiminnan parsiminen on kuitenkin mahdollista.

# ulkoinen laskuohjelma ei saa olettaa mitään, ei rajoittaa mitään ja on oltava valmis määräämään täysin naurettavatkin asiat sillä muuten ne voivat periä arvonsa jostain muualta. Matematiikan sääntöjä on noudatettava mahdollisimman orjallisesti.

# sisääntulon mielekkyydestäkään ei saa olettaa mitään vaan kaikkeen ihmeellisyyteen on varauduttava. Esimerkiksi merkintä -0. on hyväksyttävä nollaksi ja -- on hyväksyttävä plussaksi.

# vastauksessa on lopputulos numerona kahdella viimeisellä "rivillä". Toiseksiviimeinen on tämän skiptin antama tulos. Viimeinen numero on se vastaus johon se "koulussa" pyöristettäisiin. Kertomia ei ole pyöristetty sillä ne ovat aina kokonaislukuja sillä desimaalikertomien kaavaa ei tässä skriptissä ole. Myöskään imaginaarisia arvoja ei käsitellä.

set +H # jos tämä puuttuisi niin kertoman merkki: ! aiheuttaisi virheen paitsi kaavan viimeisenä merkkinä
unset command_not_found_handle # poistaa huomautukset mallia: tarkoititko käskyä xxx paketissa yyy
export BC_LINE_LENGTH=0 # jotta bc tulostaisi koko tulosteen yhtenä pötkönä ilman kenoja.
 
trap 'laske "$BASH_COMMAND"' 1 ERR
# trap 'echo virherivi:${LINENO[@]};echo ${FUNCNAME[@]} ; read' ERR # virheenmetsästyksessä
save_traps=$(trap) # koe
echo Tämä pääte osaa nyt matematiikkaa. Ohjeita ja esimerkkejä saat käskyllä: laske 

function laske () { # Tuloparametrina on laskukaava. Tulostaa näytölle ja asettaa kutsuttujen funktioiden nimiset muuttujat ja tuloksen muuttujaan: tulos.
stty sane # <ctrl+j>stty sane<ctrl+j> # echo <ctrl-v><esc>c<enter> # reset # palauttaa päätteen järkiinsä
[[ ! "$1" ]] && echo "- Niin tämä kuin kaikki muutkin BASH-skriptit toimivat ainoastaan päätteessä (terminal). Pääte oppii matematiikkaa kun päätteesssä oltaessa siinä annetaan käsky(piste kuuluu käskyyn): . polku/matemaattiset_funktiot
- siis päätteeseen voi silloin kirjoittaa esimerkiksi: 1+1  ja kun painaa return niin näytölle tulee: 2. 
- muuten Ubuntussa pääte aukeaa kun milloinhyvänsä kun painaa yhtaikaa nappuloita: Ctrl - Alt - t
- aikaisemmin päätteessäannettuja käskyjä voi selata nuolinäppäimillä.
- mikäli tässä skriptissä antaa ratkaistavaksi matemaattisen mahdottomuuden alkaa näyttö sekoilla. Silloin on viisainta sulkea se pääte ja avata uusi.
- BASH:in virheviesteistä tulee vaikeaselkoisempia. Vanhan toiminnan saa palautettua lopettamalla päätteen jossa tämä matematiikka toimii ja avaamalla uuden päätteen. 
- laskuissa on 66 desimaalia jollei käskyllä: des--- toisin määrätä. 
- kokonaisosan numeromäärä on aina rajoittamaton. Desimaalipisteen jälkeisen osan peränollia ei tulosteta.
- joskus se kuinka monella numerolla laskun alkuarvot annetaan vaikuttaa lopputulokseen paljonkin. Tällä ohjelmalla asiasta saa pätevän käsityksen.
- sallitut operaattorit: +, -, *, / ja ^ Näissä laskuissa ^ on potenssiinkorotus, esimerkiksi 3^0.5.
- laskut lasketaan sieventämättä, käyttämättä matematiikan oikopolkuja - esimerkiksi että sin^2+cos^2=1 . Tulos on siten luotettavampi mutta tulokset saadaan paljon hitaammin.   
- funktiot: sin, asin, sinh, cos, acos, cosh, tan, atan, tanh, sqrt, log, ln, exp, abs, int, e, pi, !, aa (10 järjestelmästä 2 järjestelmään), bb (2 järjestelmästä 10 järjestelmään), des(desimaalien määrä), deg, rad ja sci. Ja teoriassa uusien funktioiden lisääminen on helppoa.
- merkitätavat noudattavat normaaleja matematiikan sääntöjä. Sulkuina on kuitenkin käytettävä hakasulkuja. 
- syötettävien lukujen esitysmuoto voi olla tieteellinenkin, esimerkiksi: 1.23e6. Ohjelma osaa erottaa koska e tarkoittaa luonnollisen lukujärjestelmän kantalukua e.
- desimaalien ja radiaanien määräämis-esimerkki: des256radsin0.511;degsin0.511 .  

testilaskuja toimiminnan oikeellisuuden toteamiseksi:
-1*log.001-[[2*6!+1]/1.441e3]+[[sin210-cos60]*tan60*2]/[3^.5]*ln[e^-pi]/pi-e^[2*ln2] -> 0
des256ln[e^ln[e^ln[e^ln[e^ln[e^ln[e^ln[e^ln[e^-pi]]]]]]]]+pi -> 0;  
2+1.1e2+e-2.7 -> 112.018....
des256[6^-6^6.1^6^-5.9^6^6]-[6^-6^6.1^6^-5.9^6^6] -> 0. 
[[sin30]^2+[cos30]^2-1]+[log[5*8]-log5-log8]+[log[5/8]-log5+log8]+[log[5/8]-log5+log8]
sin[30^2]+cos[30^2]+1 -> 0
10001!/10002!-1/10002 -> 0
1.1^2.1-e^[2.1*ln1.1] -> 0
des1200aa[[2^999-1]/2^999] -> .<ja tuhat ykköstä>  (desimaaliasetus 2200 ja muunnos kaksijärjestelmään)
[sin[asin.1]]-asin[sin.1]+[atan[tan.1]]-tan[atan.1] -> 0 sekä deg etta rad
- edellisen laskun tulokseen käänteisluku tulostuu kun antaa laskuksi pelkän 1:n
- kyllä explisiittisestäkin muodosta voidaan ratkaista: x=0.5; sin \$x" && return

[[ "$1" = 1 ]] && tulos='1/'$tulos || tulos="$1"
tulos=$(echo $tulos | sed 's/\,/\./g') # muutetaan desimaalipilkut pisteiksi
[[ $(tr -dc '\[' <<<"$tulos" | awk '{ print length; }') -ne $(tr -dc '\]' <<<"$tulos" | awk '{ print length; }') ]] && echo 'sulut epätasapainossa' && return
[[ -z $sulkujaratkaisematta ]] && {
sulkujaratkaisematta=1
 
lasketaan_radiaaneissa=${lasketaan_radiaaneissa:-0} # toimintaan asteissa ellei toimintamuodoksi peritä radiaaneja.
desimaaleja=$(echo $tulos | grep -Po '(?<=des)[0-9]*' ) && tulos=${tulos//des$desimaaleja}
desimaaleja=${desimaaleja:-66} # laskujen desimaaliluku on 66 ellei peritä toista arvoa. 
desimaaleja=$((desimaaleja+5)) # koelisäys

tulos=${tulos#+}    # poistetaan laskun edestä merkki + jos sellainen on
tulos=${tulos%% #*} # poistetaan peräkommentit - peräkommentin edessä on aina välilyönti
tulos=$(echo $tulos | tr -d \' | tr "(" '[' | tr ")" ']' ) # poistetaan heittomerkki j5/ba muunnetaan kaarisulut hakasuluiksi.
tulos=${tulos//++/+}; tulos=${tulos//\*+/\*}; tulos=${tulos//\/+/\/}; tulos=${tulos//\^+/\^}; tulos=${tulos//\*\*/\^};


[[ $(echo $tulos | grep rad) ]] && lasketaan_radiaaneissa=1 && tulos=${tulos//rad} 
[[ $(echo $tulos | grep deg) ]] && lasketaan_radiaaneissa=0 && tulos=${tulos//deg} 

# muutetaan luonnollisen järjestelmän kantaluku e lukuarvoonsa kaikkialla. Siis luvut kuten tuo e kaavassa: 1+e^2
e_numeroina=$(echo "scale=$desimaaleja; e(1)" | bc -l)
tulos=$(echo $tulos | sed "s/\be\b/$e_numeroina/g")
# muutetaan pi (ympyrän kehä/halkaisija) lukuarvoonsa kaikkialla
pi_numeroina=$(echo "scale=$desimaaleja; 4*a(1)" | bc -l)
tulos=$(echo $tulos | sed "s/\bpi\b/$pi_numeroina/g") 
} # vastaava alku-sulku on rivillä 43 elikä rivillä jolla on teksti: [[ -z sulkujaratkaisematta ]] && {

# muuta kaikki tieteelliset esitysmuodot numeroiksi heti kun "eksponentti" on ratkaistu (niinkuin: 1.23e5 -> 123000) 
muuta_tieteelliset_esitystykset_numeroiksi

tput cuu1; tput el; echo # kursori ylös rivinverran ja rivin tyhjennys
[[ $(echo $tulos | tr -d +-. | grep "/0*$") ]] && echo "jako nollalla, epämääräinen tulos" && return

etsi_laskukaavasta_ratkaisukelpoinen_sulku_ja_ratkaise_se

for funktiolaji in $(echo $tulos | tr [0-9/*+-^] " " ); do
 erota_sulun_seuraavasta_funktiosta_parametrit_ja_kutsu_funktiota $funktiolaji ; done

# ratkaise x^y kaikkialla missä x ja y on ratkaistu numeroiksi; siis sulut ratkottu
apu=$(echo $tulos | grep -o [0-9.][0-9.]*^[0-9.+-][0-9.]*) # | tr "\n" " " | awk '{print $1}')
while [[  $apu != "" ]] ; do ratkaise_eksponentti $apu; apu=$(echo $tulos | grep -o [0-9.][0-9.]*^[0-9.+-][0-9.]*); done
# mikä on seuraavan lauseen merkitys ? Laskee tuloksen silloin kun jäljellä on enää numeroita?
[[ $(echo $tulos | tr -d \.[0-9]) ]] && tulos=${tulos//--/+} && tulos=$(echo "obase=10;ibase=10;scale=$desimaaleja ; $tulos" | bc -l) && [[ $vanha_tulos != $tulos ]] &&  tulosta $tulos && vanha_tulos=$tulos
[[ "${#FUNCNAME[@]}" = 1 ]] && unset vanha_tulos && unset sulkujaratkaisematta && siisti_lopputulos &&  return # viimeisellä kierroksella funktio-pinossa on yksi jäsen ja tulos voidaan pyöristää
}

function siisti_lopputulos () {
desi1=$(($desimaaleja-4)) # pyöristettävä desimaali   
[[ ${tulos:0:1} == "-" ]] && miinusalussa=-1 || miinusalussa=1 
[[ $(echo $tulos | tr -d 0.,+-) = '' ]] && echo pyöristämättä: 0 && return
echo -n pyöristettynä: ;echo $(echo "scale=$desimaaleja; $tulos+$miinusalussa*5*10^-$desi1" | bc -l) | cut -c -$(($desimaaleja-4)) | sed 's/0*$//g;s/\.$//g;s/^-$/0/g' | sed 's/^[[:punct:]]*$/0/g' # desimaaliosan pyöristys oikealla tavalla, turhien peränollien poistaminen desimaaliosan perästä ja luvun perässä olevan yksinäisen desimaalipisteenkin poistaminen ja vaihtamalla tyhjä tulos nollaksi ja muuttamalla pelkkä miinusmerkki nollaksi 
# [[ $funktiolaji == ! ]] && echo $tulos | bc | cut -d. -f1 | sed 's/^$/0/g;s/^-$/0/g' && return # kertoma on aina kokonaisluku joten sitä ei pyöristetä. tarvitaanko?
}

function erota_sulun_seuraavasta_funktiosta_parametrit_ja_kutsu_funktiota () {
[[ ! $(declare | grep $funktiolaji' \(\)') ]] && echo tuntematon funktio && return
[[ $funktiolaji = ! ]] && apu=$(echo ${tulos%%\!*}  | sed 's/\^/ /g;s/\*/ /g;s/\// /g;s/\+/ /g;s/\-/ /g') && numero=${apu##* }
[[ $funktiolaji != ! ]] && apu=$(echo ${tulos#*$funktiolaji} | sed  's/\^/ /g;s/\*/ /g;s/\// /g;s/\+/ /g;s/\-/ /g') && numero=${apu%% *}
[[ $numero = "" ]] && apuu=$(echo ${tulos#*$funktiolaji}) && apu=${apuu:0:1}${apu:1} && numero=${apu%% *} # palautetaan operaattoreita poistettaessa hävinnyt merkki
kutsu="$funktiolaji $numero"; arvo=$($kutsu); korvattava=$funktiolaji$numero;[[ $funktiolaji = ! ]] && korvattava=$numero$funktiolaji;tulos=$(echo $tulos | sed "s/$korvattava/$arvo/g")
}

function tulosta () { #  mikäli luvussa on desimaalipiste niin poistetaan peränollat ja pistekin jos se jää loppuun yksikseen
# ei vaikuta S(( $? )) && return
vanha_tulos=$1; [[ $vanha_tulos != $1 ]] && return
[[ ${1%%\.*} != $1 ]] && echo $1 | sed 's/0*$//g;s/\.$//g' || echo $1  # peränollien poisto ja desimaalipisteen poisto tarvittaessa
}

function ratkaise_eksponentti () { # kokonais-exsponenteille bc käyttää tarkkaa eksponentaatiota mutta se ei hyväksy desimaalisia exponentteja. Tässä desimaaliexponentit ohjataan käyttämään niille soveltuvaa hieman hitaanpaa ja epätarkempaa desimaali-eksponentiaatiota.
kantaluku=${1%%^*} 
exponentti=${1##*^}
[[ $(echo $exponentti | grep "\." ) ]] && valitulos=$(echo "scale=$desimaaleja; e($exponentti*l($kantaluku))" | bc -l) || valitulos=$(echo "scale=$desimaaleja; $kantaluku^$exponentti" | bc -l)
korvattava=$kantaluku"\^"$exponentti; tulos=${tulos//$korvattava/$valitulos}   
tulosta $tulos
}
 
function etsi_laskukaavasta_ratkaisukelpoinen_sulku_ja_ratkaise_se  () {
# raja=112\101\116\116\101\114\105\73\73\73
while [[ $tulos != $(echo $tulos | tr -d []) ]]; do
ilman_sulkuja=$(echo $tulos | sed 's/\].*//g;s/.*\[//g') # tämä lause etsii ratkaisukelpoisen sulun
apu=$(echo $tulos | grep -Fob -- $ilman_sulkuja)
monennestako_merkista=${apu%%\:*}
monenteenko_merkkiin=$(echo $monennestako_merkista+${#ilman_sulkuja} | bc )
tulosta $tulos
tulos_alussa="$tulos" 
tulos=$(echo $tulos | tr -d []) 
laske $ilman_sulkuja
tulos=${tulos_alussa:0:$monennestako_merkista-1}$tulos${tulos_alussa:$monenteenko_merkkiin+1}; echo $tulos
# muuta_tieteelliset_esitystykset_numeroiksi # tarvitaanko tässäkohtaa?
done
}

function muuta_tieteelliset_esitystykset_numeroiksi() { # ratkaistaan luvut mallia 1.23e18
apu=$(echo $tulos | grep -o  [.0-9]*e[.0-9+-]* | awk '{print $1}')
while [[ $apu ]] ; do arvo=$(echo "scale=$desimaaleja; $(echo $apu | sed "s/e/\*10\^/g")" | bc -l); tulos=${tulos//$apu/$arvo} ; apu=$(echo $tulos | grep -o  [.0-9]*e[0-9+-]* | awk '{print $1}'); done 
}

function tan () {
asteluku=$(echo ${1#+}) # jos asteluvun edessä on + niin  poistetaan se
(( $lasketaan_radiaaneissa )) && tan=$(echo "scale=$desimaaleja; s($asteluku)/c($asteluku)" | bc -l ) || tan=$(echo "scale=$desimaaleja; s($asteluku*$pi_numeroina/180)/c($asteluku*$pi_numeroina/180)" | bc -l)  ; tulosta $tan 
}

function aa () { # Lukumuunnos kymmenjärjestelmästä kaksijärjestelmään. Toimii myös desimaaliluvuille. Käännettävällä luvulla voi olla etumerkkikin. Muunnoksen suorittaa matematiikkaohjelma bc joka onkin kokonaisluvuille ihanteellinen. On se ihateellinen desimaaliluvuillekin, mutta sille täytyy desimaalilukujen kyseessä ollen antaa lisämääreitä.  

# Desimaalilukujen peränollia ei esitetä joten desimaalien perään täytyy lisätä niin monta nollaa kuin muunnettavassa kymmenjärjestelmäluvussa voisi olla - jos niitä nollia tulee liikaakin niin se ei merkitse juuri mitään. Siis kokonaislukuihin ei lisätä mitään.

# Muuntaminen tapahtuu tämänjälkeen oikein mutta eihän se näy kokonaisuudessaan vaan katkaistaan desimaaliasetuksen kohdalta matematiikka_funktioiden toimesta. Matematiikka_funktioiden desimaaliasetukseksi tuleekin määrätä 4 kertaa suurempi arvo kuin kymmenjärjestelmän desimaaliasetus. Siis käskyksi tulee esimerkiksi muunnettaessa luku .24: aa.24des264 

[[ $(echo $1 | tr -cd . ) ]] && apu=$1$(printf "%0"$desimaaleja"d\n") || apu=$1 # onko desimaalipistettä
# scale:n määrääminen suoraan ei toimi aina, esimerkiksi .000001;stä tulee .00000000000000000001
# jos halutaan matematiikka_funktioiden näyttävän tuloksesta kaikki 264 desimaalia täytyy käsky kirjoittaa: aa.000001des264 
aa=$(echo "ibase=10;obase=2;$apu" | bc -l) ; tulosta $aa
}

function bb () { # muunnos kaksijärjestelmästä kymmenjärjestelmään. Sopii myös desimaaliluvuille. Käännettävällä luvulla voi olla etumerkkikin.
# bc:n autoscale määrää scale:n arvoksi tulevan luvun desimaalien määrän. Ja se riittää aina.
bb=$(echo "obase=10;ibase=2;$1" | bc -l) ; tulosta $bb # scale=$((2*$desimaaleja))
}

function cos () {
asteluku=$(echo ${1#+}) # jos asteluvun edessä on + niin  poistetaan se
(( $lasketaan_radiaaneissa )) && cos=$(echo "scale=$desimaaleja; c($asteluku)" | bc -l) || cos=$(echo "scale=$desimaaleja; c($asteluku*$pi_numeroina/180)" | bc -l) ; tulosta $cos
}

function log () { # briggsin logaritmi
[[ $(echo $1 | sed 's/0*$//g;s/\.$//g') == 1 ]] && log=0 || log=$(echo "scale=$desimaaleja; l($1)/l(10)" | bc -l); tulosta $log;
}

function ln () { # e-kantainen logaritmi
[[ $(echo $1 | sed 's/0*$//g ;s/\.$//g') == 1 ]] && ln=0 ||
ln=$(echo "scale=$desimaaleja; l($1)" | bc -l); tulosta $ln 
}

function sqrt () { # neliöjuuri
[[ $(echo $1 | tr -cd - ) ]] && exit
sqrt=$(echo "scale=$desimaaleja; sqrt($1)" | bc -l); tulosta $sqrt
}

function ! () {
(( $1 )) && kertoma=$(seq -s* $1 | bc ) || kertoma=1; tulosta $kertoma
# oli [ $1 -eq 0 ]] && kertoma=1 || kertoma=$(seq -s* $1 | bc | tr -d '\\\n'); tulosta $kertoma
}

function atan () { # arctan
(( $lasketaan_radiaaneissa )) && atan=$(echo "scale=$desimaaleja; a($1)" | bc -l) || atan=$(echo "scale=$desimaaleja; a($1)*180/$pi_numeroina" | bc -l) ; tulosta $atan
}

function sin () {
asteluku=$(echo ${1#+}) # jos asteluvun edessä on + niin  poistetaan se
(( $lasketaan_radiaaneissa )) && sin=$(echo "scale=${desimaaleja:-66}; s($asteluku)" | bc -l) || sin=$(echo "scale=${desimaaleja:-66}; s($asteluku*$pi_numeroina/180)" | bc -l); tulosta $sin # miksei tulos saa uutta arvoa ?
}

function acos () { # arccos # lasku on: pi/2-asin, rajuja muutoksia
viesti='acos on määritelty vain välillä -1...+1. otetaan arvoksi:'
[[ $(echo $1 '>=' 1 | bc -l) -eq 1 ]] && acos=0 && echo -n $viesti && tulota $acos && return
[[ $(echo $1 '<=' -1 | bc -l) -eq 1 ]] && acos=1 && echo -n $viesti && tulosta $acos && return
(( $lasketaan_radiaaneissa )) && acos=$(echo "scale=${desimaaleja:-66}; $pi_numeroina/2-a($apu/sqrt(1-($1*$1)))" | bc -l) || acos=$(echo "scale=${desimaaleja:-66}; 180/$pi_numeroina*($pi_numeroina/2-a($1/sqrt(1-($1*$1))))" | bc -l) 
tulosta $acos
}

function asin () { # arcsini, rajuja muutoksia
viesti='asin on määritelty vain välillä -1...+1. otetaan arvoksi:'
[[ $(echo $1 '>=' 1 | bc -l) -eq 1 ]] && acos=0 && echo -n $viesti && tulosta $acos && return
[[ $(echo $1 '<=' -1 | bc -l) -eq 1 ]] && acos=1 && echo -n $viesti && tulosta $acos && return
(( $lasketaan_radiaaneissa )) && asin=$(echo "scale=${desimaaleja:-66}; a($1/sqrt(1-($1*$1)))" | bc -l) || asin=$(echo "scale=${desimaaleja:-66}; a($1/sqrt(1-($1*$1)))*180/$pi_numeroina" | bc -l) 
tulosta $asin
}

function sinh () { # korvauskaava on: ( ex - e-x )/2
sinh=$(echo "scale=${desimaaleja:-66}; ($e_numeroina^$1-$e_numeroina^-$1)/2" | bc -l);tulosta $sinh
}

function cosh () { # korvauskaava on: ( e x + e -x )/2
cosh=$(echo "scale=${desimaaleja:-66}; ($e_numeroina^$1+$e_numeroina^-$1)/2" | bc -l) ; tulosta $cosh
}

function tanh () { # korvauskaava on: ( ex - e-x )/( ex + e-x )
tanh=$(echo "scale=${desimaaleja:-66};  ($e_numeroina^$1-$e_numeroina^-$1)/($e_numeroina^$1+$e_numeroina^-$1)" | bc -l) ; tulosta $tanh
}

function abs () { # tämä poistaa etumerkin, myös plussan
abs=$1; abs=$(echo ${abs#[-+]}); tulosta $abs
}

function int () { # muuttujan kokonaisluku-osa
[[ ${1:0:1} != \. ]] && int=$(echo $1 | cut -d. -f1 ) || int=0;  tulosta $int | sed 's/[+-]0/0/g;s/^-$/0/g'
}
 
function sci () { # annetaan yksinään kun lasku on suoritettu. Muuttaa tulostuksen tieteellseen muotoon
echo $(printf "%e\n" $(echo $tulos | sed 's/\./\,/g')) | sed 's/\,/\./g'
}


