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

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

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

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

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

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

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

3 ответа

Решение

Если нет причины делить знаменатель на 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*6)/8) знак равно 0 вместо 0.75, Вы тогда пытаетесь разделить (2*2) тем 0, давая вам ошибку "Делить на ноль".

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

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

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

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

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

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.
Другие вопросы по тегам