Ответ 1
В Lua нет встроенной функции math.round(), но вы можете сделать следующее:
print(math.floor(a+0.5))
.
Каков наилучший эффективный способ округлить число, а затем усечь его (удалить после запятой после запятой)?
например, если десятичная цифра выше 0,5 (то есть 0,6, 0,7 и т.д.), я хочу округлить, а затем усечь (случай 1). В противном случае я хотел бы усечь (случай 2)
for example:
232.98266601563 => after rounding and truncate = 233 (case 1)
232.49445450000 => after rounding and truncate = 232 (case 2)
232.50000000000 => after rounding and truncate = 232 (case 2)
В Lua нет встроенной функции math.round(), но вы можете сделать следующее:
print(math.floor(a+0.5))
.
Трюк, полезный для округления десятичных цифр, отличных от целых чисел, должен передать значение через форматированный текст ASCII и использовать строку формата %f
для указания желаемого округления. Например
mils = tonumber(string.format("%.3f", exact))
будет округлять произвольное значение в exact
до кратного 0.001.
Аналогичный результат может быть получен с масштабированием до и после использования одного из math.floor()
или math.ceil()
, но получение информации в соответствии с вашими ожиданиями, связанными с обработкой краевых случаев, может быть сложным. Не то, чтобы это не проблема с string.format()
, но большая работа заставила его произвести ожидаемые результаты.
Округление до кратного чего-то, кроме десяти, по-прежнему потребует масштабирования и все еще имеет все сложные случаи. Один из подходов, который просто выразить и имеет устойчивое поведение, состоит в том, чтобы написать
function round(exact, quantum)
local quant,frac = math.modf(exact/quantum)
return quantum * (quant + (frac > 0.5 and 1 or 0))
end
и подстройте точное условие на frac
(и, возможно, знак exact
), чтобы получить нужные вам края.
Чтобы также поддерживать отрицательные числа, используйте это:
function round(x)
return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
Должно быть math.ceil(a-0.5)
правильно обрабатывать полуцелые числа
Здесь одно для округления до произвольного числа цифр (0, если не определено):
function round(x, n)
n = math.pow(10, n or 0)
x = x * n
if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end
return x / n
end
Для плохого округления (обрезка конца):
function round(number)
return number - (number % 1)
end
Ну, если хочешь, можешь расширить это для хорошего округления.
function round(number)
if (number - (number % 0.1)) - (number - (number % 1)) < 0.5 then
number = number - (number % 1)
else
number = (number - (number % 1)) + 1
end
return number
end
print(round(3.1))
print(round(math.pi))
print(round(42))
print(round(4.5))
print(round(4.6))
Ожидаемые результаты:
3
, 3
, 42
, 5
, 5
Мне нравится ответ выше RBerteig: mils = tonumber(string.format("%.3f", exact))
.
Расширил его до вызова функции и добавил значение точности.
function round(number, precision)
local fmtStr = string.format('%%0.%sf',precision)
number = string.format(fmtStr,number)
return number
end
Если ваш Lua использует поплавки IEC-559 (он же IEEE-754) двойной точности, как это делают большинство, и ваши числа относительно невелики (метод гарантированно работает для входов между -2 50 и 2 50), следующий эффективный код выполнит округление с использованием текущего режима округления FPU, который обычно округляется до ближайшего, связан с четным:
local function round(num)
return num + (2^52 + 2^51) - (2^52 + 2^51)
end
Например, если для FPU установлено значение округления до ближайшего или даже четного, этот unit тест выводит "Все тесты пройдены":
local function testnum(num, expected)
if round(num) ~= expected then
error(("Failure rounding %.17g, expected %.17g, actual %.17g")
:format(num+0, expected+0, round(num)+0))
end
end
local function test(num, expected)
testnum(num, expected)
testnum(-num, -expected)
end
test(0, 0)
test(0.2, 0)
test(0.4, 0)
-- Most rounding algorithms you find on the net fail this one:
test(0.49999999999999994, 0)
-- Ties are rounded to the nearest even number, rather than always up:
test(0.5, 0)
test(0.5000000000000001, 1)
test(1.4999999999999998, 1)
test(1.5, 2)
test(2.5, 2)
test(3.5, 4)
test(2^50-0.5, 2^50)
test(2^50-1.5, 2^50-2)
print("All tests passed")
Вот еще один (конечно, менее эффективный) алгоритм, который выполняет такое же округление FPU, но работает для всех чисел:
local function round(num)
local ofs = 2^52
if math.abs(num) > ofs then
return num
end
return num < 0 and num - ofs + ofs or num + ofs - ofs
end