带有小数位数的floor和ceil函数

24

我需要将一个浮点数保留指定位数的小数。

因此:

2.1235 with 2 decimals --> 2.12
2.1276 with 2 decimals --> 2.12  (round would give 2.13 which is not what I need)

np.round函数接受一个decimals参数,但似乎函数ceilfloor不接受小数位数,并始终返回一个没有小数的数字。

当然,我可以将数字乘以10^ndecimals,然后应用floor函数,最后再除以10^ndecimals

new_value = np.floor(old_value * 10**ndecimals) / 10**ndecimals

但我想知道是否有内置函数可以完成此操作,而无需执行这些操作。


可能是重复的问题,参考https://dev59.com/1nRB5IYBdhLWcg3w9Lzn。 - techytushar
这个问题要求将一个数字四舍五入。我不想四舍五入。 - user2261062
4个回答

24

Python内置的ceil/floor函数和numpy中的版本都不支持精度选项。

一个提示是可以重用round函数代替乘除法(这样应该更快):

def my_ceil(a, precision=0):
    return np.round(a + 0.5 * 10**(-precision), precision)

def my_floor(a, precision=0):
    return np.round(a - 0.5 * 10**(-precision), precision)

更新: 正如@aschipfl指出的那样,对于整数值np.round将四舍五入到最近的偶数,这会导致意外的结果,例如my_ceil(11)将返回12。这里是一个更新的解决方案,解决了这个问题:

def my_ceil(a, precision=0):
    return np.true_divide(np.ceil(a * 10**precision), 10**precision)

def my_floor(a, precision=0):
    return np.true_divide(np.floor(a * 10**precision), 10**precision)

1
我喜欢这个解决方案。你有什么想法为什么 ceilfloor 没有小数参数?如果实现允许的话,它会很有用。 - user2261062
2
我不知道。也许是因为其他语言没有它。我同意有这个功能会很有帮助。 - Marat
提醒一下,由于Python通过显示四舍五入的值而不是真实的机器值来保持浮点数可管理(请参见[https://docs.python.org/2/tutorial/floatingpoint.html]),因此如果您打印结果,则此解决方案似乎有效。但是,当我使用Python内置的十进制模块显示存储在浮点数中的精确值时,我注意到它仍然不是完美的floor或ceil。如果您要在计算floor或ceil后应用进一步操作,则这是可以接受的,但可能会产生影响。 - B. Ackerman
$ Decimal(np.round(1.128345345 + 0.5 * 10**(-2), 2)) Decimal('1.12999999999999989341858963598497211933135986328125') - B. Ackerman
a是整数时,np.round() 四舍五入到最近的偶数,这样不会返回错误结果吗? - aschipfl
显示剩余4条评论

5

这似乎可以工作(不需要导入任何模块,而且使用 // 运算符比numpy更快,因为它只是返回了除法的下取整):

a = 2.338888
n_decimals = 2
a = ((a*10**n_decimals)//1)/(10**n_decimals)

是的,这几乎和我正在做的一样。我更喜欢使用 floor,因为有时我会使用 ceil,而且我可以使用相同的语法使代码更易读。 - user2261062
@SembeiNorimaki 这个方法的运行时间比你在问题中提到的numpy方法少了一半左右,比被接受的答案(这是三种方法中最慢的)快13-14倍。 使用这种方法创建自定义函数是最好的方法。 - tsb5555

0
如果正则表达式是一个选项,你可以试一下这个:
import re

def truncate(n, d):
  return float(re.search('\d+\.\d{}'.format(d), str(float(n)))[0])

print(truncate(2.1235, 2))
print(truncate(2.1276, 2))

输出:

2.12
2.12

使用 str.split 的另一种解决方案:

def truncate(n, d):
  s = str(float(n)).split('.')
  return float('{}.{}'.format(s[0], s[1][:d]))

print(truncate(2.1235, 2))
print(truncate(2.1276, 2))

输出:

2.12
2.12

1
这个方法可以用,但我认为它比我目前所做的乘法和除法更加复杂。 - user2261062
1
将一个 int 传递给这个函数可能会导致意外情况(如果不能保证始终得到浮点数...) - Jon Clements
@JonClements 你说得对,将 n 强制转换为 float 可以解决这个问题。 - DjaouadNM

-2

对于 C++ 开发人员或者对我起作用的一般解决方案:

float a, b;

// a = 2.05
// b = 2

c = (ceil((a-b)*1000))/1000;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接