当前位置: 首页 > 面试题库 >

比较NumPy arange和自定义范围函数以产生具有十进制增量的范围

陶永望
2023-03-14
问题内容

这是一个自定义函数,允许逐步执行十进制增量:

def my_range(start, stop, step):
    i = start
    while i < stop:
        yield i
        i += step

它是这样的:

out = list(my_range(0, 1, 0.1))
print(out)

[0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999]

现在,这不足为奇了。可以理解,这种情况是由于浮点数不准确而导致的,0.1并且在内存中没有确切的表示形式。因此,这些精度误差是可以理解的。

就拿numpy在另一方面:

import numpy as np

out = np.arange(0, 1, 0.1)
print(out)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

有趣的是,这里没有引入明显的不精确度。我认为这可能与__repr__节目内容有关,因此为了确认这一点,我尝试了以下操作:

x = list(my_range(0, 1.1, 0.1))[-1]
print(x.is_integer())

False

x = list(np.arange(0, 1.1, 0.1))[-1]
print(x.is_integer())

True

因此,我的函数返回了一个不正确的上限值(应该是,1.0但实际上是1.0999999999999999),但np.arange正确地做到了。

我知道浮点数学运算是否损坏?但是这个问题的重点是:

numpy如何做到这一点?


问题答案:

端点之间的差异是因为NumPy会预先计算长度而不是临时计算,因为它需要预分配数组。您可以在_calc_length助手中看到它。它不会在到达结束参数时停止,而会在到达预定长度时停止。

预先计算长度并不能使您避免非整数步骤的问题,并且无论如何您都会经常得到“错误的”端点,例如,使用numpy.arange(0.0, 2.1, 0.3)

In [46]: numpy.arange(0.0, 2.1, 0.3)
Out[46]: array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8,  2.1])

使用它要安全得多numpy.linspace,您可以在其中而不是步长上说要多少个元素以及是否要包括正确的端点。

在计算元素时,NumPy似乎没有舍入错误,但这仅仅是由于不同的显示逻辑。NumPy比其更积极地截断显示的精度float.__repr__。如果tolist用于获取普通的Python标量的普通列表(以及普通的float显示逻辑),则可以看到NumPy也遇到了舍入错误:

In [47]: numpy.arange(0, 1, 0.1).tolist()
Out[47]: 
[0.0,
 0.1,
 0.2,
 0.30000000000000004,
 0.4,
 0.5,
 0.6000000000000001,
 0.7000000000000001,
 0.8,
 0.9]

舍入误差略有 不同
(例如,在.6和.7中而不是.8和.9中),因为它还使用了不同的方法来计算元素,这些元素在相关dtype的fill函数中实现。

fill函数实现的优点是,它使用start + i*step而不是重复添加步骤,从而避免了每次添加都会累积错误。但是,它的缺点是(出于令人信服的原因,我无法看到)它会从前两个元素重新计算步长,而不是将步长作为参数,因此它可能在前一步中失去很多精度。



 类似资料:
  • 问题 如果你想知道某个变量是否在给定的范围内。 解决方案 使用 CoffeeScript 的连缀比较语法。 maxDwarfism = 147 minAcromegaly = 213 height = 180 normalHeight = maxDwarfism < height < minAcromegaly # => true 讨论 这是从 Python 中借鉴过来的一个很棒的特性。利用这

  • 我想知道列表中是否有一个等效语句来执行以下操作。在MATLAB中,我将执行以下操作 简而言之,我有一个初始值,一个最终值和一个增量。我需要创建一个数组(我读到它相当于python中的列表)并打印到文件中。

  • 问题内容: 在MySQL中,如果我有日期范围的列表(范围开始和范围结束)。例如 我想检查另一个日期范围是否包含列表中已经存在的任何范围,我该怎么做? 例如 问题答案: 这是一个经典问题,如果您逆转逻辑,实际上会更容易。 让我举一个例子。 我将在此处发布一个时间段,以及其他时间段的所有不同变体以某种方式重叠。 另一方面,让我发布所有不重叠的内容: 因此,如果您简单地将比较简化为: 那么您将找到所有不

  • 有人能解释一下CDI范围注释在生产者中的作用吗?他们似乎什么也做不了。 这些,自然地,在启动时给出了这个(省略的)错误。 WELD-001409:类型的依赖关系不明确。可能的依赖关系: 带有限定符[@Any@Default]的生产者方法[Thing]声明为[[BackedAnnotatedMethod]@生成公共pkg。测验东西制作人。thingMaker(), 因此,尽管“RequestScop

  • 问题 你想定义一个数组的范围。 解决方案 在 CoffeeScript 中,有两种方式定义数组元素的范围。 myArray = [1..10] # => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] myArray = [1...10] # => [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] 要想反转元素的范围,则可以写成下面这样。 myLargeArray =

  • 问题内容: 我有两个值: [3:6] 我试图在Golang中玩一些游戏,但是我找不到能够根据这些值创建数组的好方法。 我要实现的目标是: 问题答案: 您可以利用该构造使其更紧凑甚至更快: 出于好奇,可以在不使用循环变量的情况下实现循环,但是这样会更慢,并且代码也更长。通过递减: 或递增:

  • 问题内容: 我是Java的新手,我想问这个问题只是为了帮助我更好地理解OOP。 假设我要定义一个名为“小时”的新类。要实例化该类,我们需要指定一个整数以指示该实例的小时数。 因此,当我们在此处定义小时类别时,构造函数的参数应在[0,24)范围内。如果定义了超出此范围的参数,我们如何定义这样的参数?我可以抛出错误吗? 谢谢。 问题答案: 如果您希望 编译器 捕获错误,则可以为小时定义一个枚举,然后将

  • 问题内容: 我想创建自己的自定义范围bean,它将使用HTTP会话(类似于Flash作用域)。 根据Spring手册,我需要实现org.springframework.beans.factory.config.Scope接口 我的问题是如何在此bean中获取HTTP会话?我知道,如果我在ServletContext范围内创建bean,则将实现ServletContextAware接口。 请帮忙 :