Wciąż szukam czystej bc
odpowiedzi na to, jak zaokrąglić tylko jedną wartość w funkcji, ale oto czysta bash
odpowiedź:
#!/bin/bash
echo "Insert the price you want to calculate:"
read float
echo "This is the price without taxes:"
embiggen() {
local int precision fraction=""
if [ "$1" != "${1#*.}" ]; then # there is a decimal point
fraction="${1#*.}" # just the digits after the dot
fi
int="${1%.*}" # the float as a truncated integer
precision="${#fraction}" # the number of fractional digits
echo $(( 10**10 * $int$fraction / 10**$precision ))
}
# round down if negative
if [ "$float" != "${float#-}" ]
then round="-5000000000"
else round="5000000000"
fi
# calculate rounded answer (sans decimal point)
answer=$(( ( `embiggen $float` * 100 + $round ) / `embiggen 1.18` ))
int=${answer%??} # the answer as a truncated integer
echo $int.${answer#$int} # reassemble with correct precision
read -p "Press any key to continue..."
Zasadniczo, to ostrożnie wyodrębnia ułamki dziesiętne, mnoży wszystko przez 100 miliardów (10¹⁰, 10**10
in bash
), dostosowuje precyzję i zaokrąglanie, dokonuje rzeczywistego podziału, dzieli z powrotem do odpowiedniej wielkości, a następnie ponownie wprowadza ułamek dziesiętny.
Krok po kroku:
W embiggen()
wyznacza funkcyjne ściętego całkowitą postaci jej argumentu $int
i zapisuje numery po kropką $fraction
. Liczba cyfr ułamkowych jest zapisana w $precision
. Mnoży matematyczne 10¹⁰ przez złączenie $int
i $fraction
, a następnie dostosowuje się, że w celu dopasowania do precyzji (np embiggen 48.86
się 10¹⁰ x 4886/100 i wraca 488600000000
który jest 488600000000).
Chcemy ostatecznej precyzji setnych, więc mnożymy pierwszą liczbę przez 100, dodajemy 5 dla celów zaokrąglania, a następnie dzielimy drugą liczbę. To zadanie $answer
pozostawia nas sto razy ostateczną odpowiedź.
Teraz musimy dodać przecinek dziesiętny. Przypisujemy nową $int
wartość $answer
wykluczeniu ostatnich dwóch cyfr, następnie echo
kropką i $answer
wykluczeniu $int
wartości, o którą już zadbano. (Nie wspominając o błędzie podświetlania składni, który sprawia, że wygląda to jak komentarz)
(Bashism: potęgowanie nie jest POSIX, więc jest to bashism. Czyste rozwiązanie POSIX wymagałoby, aby pętle dodawały zera, a nie używały potęg dziesięciu. Ponadto „embiggen” to słowo doskonale cromulant.)
Jednym z głównych powodów, dla których używam zsh
mojej powłoki jest to, że obsługuje matematykę zmiennoprzecinkową. Rozwiązanie tego pytania jest dość proste w zsh
:
printf %.2f $((float/1.18))
(Chciałbym zobaczyć, jak ktoś dodaje komentarz do tej odpowiedzi, podając sztuczkę włączenia arytmetyki zmiennoprzecinkowej bash
, ale jestem pewien, że taka funkcja jeszcze nie istnieje.)