2014-12-07 4 views
6

Я пытаюсь решить этот скрипт bash, который читает арифметическое выражение от пользователя и выводит его на экран вывода с округлением до 3 десятичных знаков в конце.bc arithmetic Ошибка

входная выборка

5+50*3/20 + (19*2)/7 

Пример вывода

17.929 

мой код

read x 
echo "scale = 3; $x" | bc -l 

, когда есть вход

5+50*3/20 + (19*2)/7 

** мой выход **

17.928 

чего машина хочет быть

17.929 

и из-за этого я получаю решение неправильно. Есть идеи ?

+0

Ваш вопрос довольно неоднозначен. Что вы называете «образцом вывода»? Что вы называете «мой вывод»? Что вы называете «машина хочет, чтобы это было»? Собственно, каков результат, который вы хотите, чтобы ваш скрипт генерировал: усеченный или округленный? –

+0

образец ввода - это вход, который машина генерирует, чтобы проверить, прав ли мой скрипт или нет, для которого он ожидает, что выход будет выходным, который является образцом вывода. и мой вывод - это результат, который генерирует мой сценарий, что мне нужно - это мой вывод, похожий на выходной образец @YvesDaoust – krrish

+0

Возможно, я не уверен, что может быть неправильно сказать, что вы не сделали объяснение менее неясным. Усечен или округлен? –

ответ

3

Ключевым моментом здесь является, чтобы убедиться в использовании Printf с спецификацией форматирования «% .3f» и printf позаботится о округлении по вашему желанию, пока «шкала = 4» для bc.

Вот скрипт, который работает:

echo -e "please enter math to calculate: \c" 
read x 
printf "%.3f\n" $(echo "scale=4;$x" | bc -l) 

Вы можете получить представление о том, что происходит с указанным решением, если вы запустите эту команду в командной строке: echo "scale=4;5+50*3/20 + (19*2)/7" | bc результат будет 17.9285. Когда этот результат предоставляется printf в качестве аргумента, функция учитывает четвертое десятичное место и округляет значение, так что отформатированный результат отображается с точностью до трех знаков после запятой и со значением 17.929.

Кроме того, это работает, тоже без трубы, перенаправив здесь документ в качестве входных данных для нашей эры, так что позволяет избежать создания подоболочки:

echo -e "please enter math to calculate: \c" 
read x 
printf "%.3f\n" $(bc -l <<< "scale=4;$x") 
+0

Может также быть последовательным 'printf '% .3f" $ (printf "scale = 4; 5 + 50 * 3/20 + (19 * 2)/7 \ n" | bc) '. ':)' –

+0

Не нужно использовать возможности форматирования printf в обоих местах. Я намеренно использую echo b/c, в этой части ничего не форматировать. С другой стороны, для округления printf «% .3f» имеет смысл. Возможно, вы захотите увидеть принятый ответ в stackoverflow.com/questions/2395284/... - – slevy1

+0

Пожалуйста, не думайте, что я говорил, что смешивание обоих было неправильным. Но вы должны думать о путанице для другого человека, размышляя («Теперь почему она использовала« printf »здесь и« эхо »там, а не« printf »в обоих местах?»). Ваше объяснение выше идеально. –

3

Вы не округляете число, вы обрезаете его.

$ echo "5+50*3/20 + (19*2)/7" | bc -l 
17.92857142857142857142 
$ echo "scale = 3; 5+50*3/20 + (19*2)/7" | bc -l 
17.928 

Единственный способ я знаю, чтобы округлить число использует awk:

$ awk 'BEGIN { rounded = sprintf("%.3f", 5+50*3/20 + (19*2)/7); print rounded }' 
17.929 

Итак, в вас пример:

read x 
awk 'BEGIN { rounded = sprintf("%.3f", $x; print rounded }' 
1

Я полностью согласен с jherran, что вы не округляя номер, вы обрезаете его. Я бы сказал, что масштаб, вероятно, просто не ведет себя так, как вы этого хотите, возможно, таким образом, чтобы никто не хотел, чтобы он себя вел.

> x="5+50*3/20 + (19*2)/7" 
> echo "$x" | bc -l 
17.92857142857142857142 
> echo "scale = 3; $x" | bc -l 
17.928 

Кроме того, because of the behaviour of scale, вы округления каждого умножения/деления отдельно от сложений.Позвольте мне доказать свою точку зрения несколькими примерами:

> echo "scale=0; 5/2" | bc -l 
2 
> echo "scale=0; 5/2 + 7/2" | bc -l 
5 
> echo "5/2 + 7/2" | bc -l 
6.00000000000000000000 

Однако масштаб без какой-либо операции также не работает. Существует уродливое обходное:

> echo "scale=0; 5.5" | bc -l 
5.5 
> echo "scale=0; 5.5/1" | bc -l 
5 

Так что буксировка происходит из этого.

  • Если вы хотите использовать шкалу bc, сделайте это только для окончательного результата, который уже вычислен, и даже тогда, остерегайтесь.

  • Помните, что округление - это то же самое, что и усечение числа + половина желаемой точности.

Давайте возьмем пример округления до ближайшего целого числа, если добавить .5 на номер, который должен быть округляется до ее целая часть будет принимать следующий целочисленное значение и усечение даст желаемого результата. Если это число должно быть округлено, то добавление .5 не изменит его целочисленное значение, и усечение даст тот же результат, что и при добавлении ничего.

Таким образом, мое решение следующим образом:

> y=$(echo "$x" | bc -l) 
> echo "scale=3; ($y+0.0005)/1" | bc -l # scale doesn't apply to the +, so we get the expected result 
17.929 

Опять же, обратите внимание, что следующее не работает (как описано выше), тем самым нарушая его в две операции действительно необходимо:

> echo "scale=3; ($x+0.0005)/1" | bc -l 
17.928 
+0

На самом деле это работа, я отметил ответ ниже, это сработало. в любом случае я так благодарен за то, что вы тратили свое время и объясняли, я понял основную концепцию, спасибо @Climbali – krrish