Пакетная операция возвращает «Ошибка деления на ноль» с отложенным расширением и допустимой операцией

780
Mathys Oliveira

Следующая строка кода выполняется через мой текущий проект:

set /a "hp = hp - ((atk*arandom)/((edef*6)/edefbonus))" 

А вот как это выглядит, когда вы заменяете переменные их значениями:

set /a "hp = 50 - ((2*2)/((1*6)/8))" 

Ответ на это - 44.666667, который должен быть округлен до 45. Но вместо этого Пакет просто говорит мне «Делить на ноль ошибок», когда код выполняется, как с версией, которая использует переменные, так и с версией, которая вместо этого использует числа.

Я действительно потерян для подсказок. Я проверил наличие неравных скобок, я проверил наличие неустановленных переменных и установлен EnabledDelayedExpansion. Так что я делаю не так ...?

0

3 ответа на вопрос

2
DickN

Если нет причины делить знаменатель на edfbonus вместо умножения на него числителя, вы можете избежать проблемы делителя нуля, переставив вычисления:

set /a "hp = hp - ((atk*arandom*edefbonus)/(edef*6))"

Внешние скобки и кавычки не нужны, и в set / a есть оператор, который сохраняет некоторые операции ввода и приводит в порядок такие выражения:

set /a hp -= atk*arandom*edefbonus/(edef*6)

Так как вы упомянули округление, я добавлю это:

При условии, что значение справа от -=оператора выше всегда положительно, самый простой способ выполнить округление:

set /a hp -= (10*atk*arandom*edefbonus/(edef*6)+5)/10

Обратите внимание, что мы умножаем на 10 до деления, а не после него, поэтому вычисление идет следующим образом:

10*2*2*8 =320 1*6 =6 320/6 =53 53+5 =58 58/10 =5 

Если мы умножим на 10 после деления, как в

set /a hp -= (atk*arandom*edefbonus/(edef*6)*10+5)/10,

расчет будет идти:

2*2*8 =32 1*6 =6 32/6 =5 (we just lost the fraction digit, so rounding won't work) 5*10 =50 50+5 =55 55/10 =5 

Тот же результат, но только потому, что округление все равно было бы округлено вниз.

1
Ƭᴇcʜιᴇ007

Пакет не может обрабатывать числа с плавающей запятой, только целые числа.

Так ((1*6)/8)= 0вместо 0.75. Затем вы пытаетесь разделить (2*2)на это 0, выдавая ошибку «Разделить на ноль».

Предлагаемое решение? Вместо этого используйте PowerShell:

PS Y:\> $hp = 50 - ((2*2)/((1*6)/8)) PS Y:\> $hp 44.6666666666667 

Связанный вопрос SU:

Связанный ТАК вопрос:

1
DavidPostill

Пакетная операция возвращает «Ошибка деления на ноль»

set /a "hp = 50 - ((2*2)/((1*6)/8))" 

Это потому что 1*6= 6и 6/8= 0.75.

А также:

Любое вычисление SET / A, которое возвращает дробный результат, будет округлено до ближайшего целого числа.

Так 0.75округляется до 0.

6/0 возвращает «Ошибка деления на ноль».


обходные

Нет реальных обходных путей, позволяющих использовать математику с плавающей запятой, кроме использования других языков сценариев.

Единственным исключением может быть, если у вас ограниченное и фиксированное количество десятичных знаков (например, 2), тогда вы можете просто умножить все на 100.

Чтобы отобразить десятичный разделитель в конечных результатах, объедините целочисленное деление на 100, затем десятичный разделитель и деление по модулю на 100:

SET Whole = Result / 100 SET "Fraction = Result %% 100" SET Result=%Whole%.%Fraction% 

Это может нарушить 32-битный лимит.

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

Исходный Math в пакетных файлах NT


Арифметические выражения (SET / a)

Поместить выражения в «кавычки» необязательно для простой арифметики, но необходимо для любого выражения, использующего логические операторы.

Любое вычисление SET / A, которое возвращает дробный результат, будет округлено до ближайшего целого числа.

Исходный набор


Дальнейшее чтение

  • Индекс AZ командной строки Windows CMD - Отличный справочник по всем вопросам, связанным с командной строкой Windows.
  • set - отображать, устанавливать или удалять переменные окружения CMD. Изменения, сделанные с помощью SET, будут сохраняться только в течение текущего сеанса CMD.