Kirjoittaja Aihe: Ohjeita shell-skriptaukseen (bash)  (Luettu 622557 kertaa)

petteriIII

  • Käyttäjä
  • Viestejä: 707
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #340 : 01.02.26 - klo:13.36 »
Tässä on 16 numeroinen neliöjuuri-laskun tarvitsema summaaja-vähentäjä. Aluksi tehdään versio joka toimii ainoastaan kokonaisluvuilla ja vasta pitkien testauksien jälkeen sitä voi alkaa sovittamaan desimaaliluvuille. Inhottavan näköistä koodia siinä on paljon - mutta BASH:iksi se on kuitenkin hyvin nopea vaikkakin muiden kielien kannalta todella hidas - tämä funktio vie aikaa alle millisekunnin - ja bc tai awk:kin kuluttaa aikaa 2-3 millisekuntia samaan laskuun - se 3ms kestää ennenkuin ne aloivat toimia.

BASH:in toiminnan tarkoitus on opettaa muunmuassa kuinka vaikeita alkeis-tehtävätkin ovat ratkaista siten että ne toimisivat aina moitteettomasti - ja nehän ovat samat kaikissa kielissä. Ja jokainen kieli on samojen matematiikan sääntöjen sitoma ja kaikki ratkaisevat tämmöisiä olemattoman kokoisia tehtäviä sammallatavoin - muut kielet tosin ratkovat ne kirjastojensa sokkeloissa ja prosessoriensa langoituksessa - joten varmaankaan et ole noita ratkaisuja nähnytkään. Mutta riittää kun tietää että niitä on.

- eihän matematiikkaa voi millään kielellä toteuttaa moitteettomasti kokonaan vaan aina tulee tilanteita joissa nikotellaan. Ja koska BASH:in on valehdeltu olevan täysin kykenemätön mihinkään eikä ole tehty ohjelmia alkeis-ongelmia ratkomaan niin että kun BASH alkaa nyt siitä missä toiset kielet olivat yli kolmekymmentä vuotta sitten niin BASH nikottelee alkuunsa ihan kaikissa tehtävissä. Mutta se hyvä puoli näissä ohjelmallisissa ratkaisuissa on että vaikka ne ovat todella hitaita niin kaiken saa lopulta toimimaan.

- kielen toiminnassa arvostetaan usein joustavuutta nopeutta enemmän - joten jos kielen perusteet ovat kunnossa niin joustavampi voittaa ilmanmuuta - ja vanhoilla käskyillä BASH on erittäin joustava - ja siitähän se riemu repesi sillä sellaista ei voi sallia että harrastelijan työkalu olisi parempi kuin ammattilaisella joten BASH:in vanhemmat veivät lapseltaan hampaat. Onneksi he eivät uskaltaneet kajota tulkkiin ja vanhat käskyt ovat tulkissa.
 
Pikku-tehtävistä tämä oli ehdottomasti elämäni työläin tehtävä - koska en kuunnellut omia puheitani siitä että vähennyslasku käsitellään ensimmäisenä - silloinkin kun toiminnan aikana saattaa jostain väli-tuloksesta tulla negatiivinen:
Koodia: [Valitse]
function summaa36 () { # ensimmäisen luvun tulee olla positiivinen ja suurempi mutta toinen pienempi luku voi olla negatiivinenkin

tulosta=: # yhdessä paikassa päätetään tulostetaanko skriptissä välituloksia missään. Vaihtoehdot:tulosta=echo ja tulosta=: . : on käsky olla tekemättä  mitään ja kuitenkin sillä voi olla parametreja aivan niinkuin echo:llakin.

luku1=$1
luku2=$2
[[ ${1:0:1} = - ]]  && merkki1=- || merkki1='+'
[[ ${2:0:1} = - ]]  && merkki2=- || merkki2='+'
luku1=${luku1//\-/}; luku2=${luku2//\-/} # poistetaan merkki -

luku1="0000000000000000000000000000000000000"$luku1; luku1=${luku1: -36:36}
luku2="0000000000000000000000000000000000000"$luku2; luku2=${luku2: -36:36}   

luku11=${luku1:0:18}; luku12=${luku1:18:18} #; [[ $luku11 -eq 0 ]] && luku11=0
luku21=${luku2:0:18}; luku22=${luku2:18:18} #; [[ $luku22 -eq 0 ]] && luku22=0                             
$tulosta annettu_luku           18_ensimmäistä_numeroa     18_viimeistä_numeroa
$tulosta $luku1 $luku11    $luku12 
$tulosta $luku2 $luku21    $luku22

alivuoto=0; ylivuoto=0
apu1=$((10#$luku12$merkki2 10#$luku22))
# [[ ${#apu1} -eq 19 ]] && { apu1=${apu1:0:18}; ylivuoto=1 ;} ; [[ $apu1 -lt 0 ]] && { apu1=$(($apu1+"100000000000000000")); alivuoto=1 ;}  # epäilyttävä
[[ $apu1 -lt 0 ]] && { apu1=$(($apu1+"1000000000000000000")); alivuoto=1 ;}; [[ ${#apu1} -eq 19 ]] && { apu1=${apu1:1:19}; ylivuoto=1 ;} ;   # epäilyttävä
apu1="000000000000000000000"${apu1#[-+]}; apu1=${apu1: -18:18}; $tulosta vähemmän merkitsevien lukujen summa: $apu1
apu2=$((10#$luku11$merkki2 10#$luku21+$ylivuoto-$alivuoto)); $tulosta enemmän merkitsevien lukujen summa: $apu2 ylivuoto: $ylivuoto alivuoto: $alivuoto

apu=$apu2${apu1#0}; echo ${apu##+(0)} ;}

# esimerkkilaskuja:
echo -e '\n\n'; time summaa36 22222222222222211111111111111111 2222222299999999999922222222221   
echo -e '\n\n'; time summaa36 22222222222222211111111111111111 -2222222299999999999922222222221
echo -e '\n\n'; time summaa36 555 -6
echo -e '\n\n'; time summaa36 555 6

-tulokset voi tarkistaa vaikka bc-llä esimerkiksi käskyllä: bc<<<"22222222222222211111111111111111+2222222299999999999922222222221"

petteriIII

  • Käyttäjä
  • Viestejä: 707
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #341 : 02.02.26 - klo:20.53 »
Osien yhteen-liittämisessä ei ollut vaikeuksia - ja se että kokonaisuus onnistui osoittaa kaikkien osien toimivan varsin hyvin - nimittäin osat vaativat toisiltaan paljon sellaista mitä ihminen ei tajua vaatia.
« Viimeksi muokattu: 03.02.26 - klo:17.32 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 707
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #342 : 03.02.26 - klo:17.42 »
Seuraavaksi keskityn jakolaskuun. Sen varsinainen laskurutiini on hyvin yksinkertainen - joten tottakai se paranisi matemaatikon käsittelyssä. Ihan raakile jakolasku vielä on ja kaipaa paljon työstämistä.

Nyt alkaa tarkentua syy miksi BASH:ia on mollattu sillä tämä jakolaskukin on nopeampi kuin bc, awk ja semmoiset. Sillä eihän noilla mitään tee jos BASH itse on parempi. Kuvottava teko se mollaaminen aikanaan oli - mutta nykyään raadoksi mollatun BASH:in mollaaminen edelleen on vain typeryyttä.

Silti tulosta verrataan tässä bc:n tulokseen sillä onhan se bc:n tulos sentään varmasti oikein - ja bc muuten toimii muuten niinkuin lasku-ohjelman pitääkin - mitä muut eivät yleensaä osaa.

Eihän tämmöisillä enää käytännön merkitystä ole mutta onhan se kiva lisämauste kun voi haistattaa Pythonille muutamissa pikkuhommissa - ja kuka tietää jos joskus monessa merkittävässäkin tehtävässä.

Nimittäin kaikki mitä olen kokeillut - anonyymeistä funktioista alkaen - on toiminut erittäin nopeasti kun ottaa huomioon että BASH:in toimimisnopeus alkaa 0.5 ms:sta. Täytyy kyllä myöntää että BASH:issa on paljon huonoakin kummallisen logiikkansa lisäksi - eihän sitä ole paljoakaan kehitetty - muuten taitaa olla todella hyvä ettei olekaan kehitetty sillä koska ei ole tajuttu mitään niin luultavasti olisi 'kehitetty' se vainaaksi.

Skripti tulostaa noin 36 desimaalia jos ei lasku-käskyssä määrää tarkkuutta - tarkkuuden voi määrätätä rajoittamattomaksi mutta eihän se vielä toimi aina virhettömästi. Esimerkiksi:
jaa 1 3
jaa 1 3 360000    # 360000 desimaalin laskeminen kestää noin 15 sekuntia.

- paljon siinä on vielä hiottavaa - esimerkiksi tuo case-looppi on toistaiseksi ihan kummallinen.
Koodia: [Valitse]

function jaa () {
desimaaliluku=36; [[ $3 ]] && desimaaliluku=$3
tulosta=: # yhdessä paikassa päätetään tulostetaanko välituloksia.  Vaihtoehdot:tulosta=echo ja tulosta=:

[[ ${1//[^.]/} ]] && luku1=$1 || luku1=$1"."
[[ ${2//[^.]/} ]] && luku2=$2 || luku2=$2"."

desimaaliosa1=${luku1##*.}
desimaaliosa2=${luku2##*.}
int1=${luku1%%.*}; #_echo x$int1
int2=${luku2%%.*}; #_echo y$int2

apu=$((${#int2}-${#int1})); $tulosta $apu  # kokonaisten lukumäärä? tämä on kelvoton
etunollia=''
case $apu in
-{1..18} ) etunollia='';; # desimaaleja=$((-1*$apu+1 )) }  ;;
0)  etunollia='';; #desimaaleja=0 ;; # apu=85; printf "%${apu}s" | tr " " 0
1)  etunollia='' ;;
2)  etunollia=0 ;;
3)  etunollia=00 ;;
4)  etunollia=000 ;;
5)  etunollia=0000 ;;
6)  etunollia=00000 ;;
7)  etunollia=000000 ;;
8)  etunollia=0000000 ;;
9)  etunollia=00000000 ;;
10) etunollia=000000000 ;;
11) etunollia=0000000000 ;;
12) etunollia=00000000000 ;;
13) etunollia=000000000000 ;;
*) desimaaleja=$((-1*$apu-1 )) ;;
esac
$tulosta etunollia:$etunollia'  desimaaleja:'$desimaaleja

luku1=$int1$desimaaliosa1
luku2=$int2$desimaaliosa2

$tulosta #luvut ilman desimaalipistettä:  ";$luku1' '$luku2

tulos='' # vain varmistus että kaikki on tuloksessa tämänjälkeen uutta
until [ ${#tulos} -gt $desimaaliluku ] ; do # muodostetaan tulos-palasia n merkkiä kerrallaan  #

apu=$(($luku1/$luku2)); [[ $apu -eq 0 ]] && apu=''; [[ ${apu:0:1} -eq 9 && ${tulos: -1} -eq 9  ]] && apu="0"$apu; tulos=$tulos${apu} ; $tulosta a$luku1' '$luku2' '$apu
luku1=$(($luku1%$luku2))'000000000000000000000000'; luku1=${luku1:0:18} ; $tulosta z$luku1
done

$tulosta "oikea tulos 140 desimaalilla esitetynä on päällä ja alla tulos tästä laskusta:"

[[ $etunollia ]] && echo .$etunollia${tulos:0} || echo ${tulos:0:$desimaaleja}.${tulos:$desimaaleja} ;}


# esimerkkilaskuja - kuten huomaat niin paljon on ihan keskeneräistä:
a=75.1234567 b=1233457; echo $(bc<<<"scale=140; $a/$b" | tr -d '\\\n')'  tämä rivi on bc:stä'; echo; time jaa $a $b 168; echo; echo
a=1233457890123.23; b=.92345678999999; echo $(bc<<<"scale=140; $a/$b" | tr -d '\\\n  tämä rivi on bc:stä'); echo; time jaa $a $b 170; echo; echo
a=1233457890123.23 b=.1234567; echo $(bc<<<"scale=140; $a/$b" | tr -d '\\\n  tämä rivi on bc:stä'); echo; time jaa $a $b 170; echo; echo
a=.1234567 1233457890123.23; echo $(bc<<<"scale=140; $a/$b" | tr -d '\\\n  tämä rivi on bc:stä'); echo; time jaa $a $b 170; echo; echo