为啥我不能在 Swift 的 reduce 中正确划分整数?

Posted

技术标签:

【中文标题】为啥我不能在 Swift 的 reduce 中正确划分整数?【英文标题】:Why can't I divide integers correctly within reduce in Swift?为什么我不能在 Swift 的 reduce 中正确划分整数? 【发布时间】:2015-11-08 08:33:15 【问题描述】:

我正在尝试使用以下代码获取 Ints 数组的平均值:

let numbers = [1,2,3,4,5]
let avg = numbers.reduce(0)  return $0 + $1 / numbers.count 
print(avg) // 1

这显然是不正确的。但是,如果我将除法移到闭包之外:

let numbers = [1,2,3,4,5]
let avg = numbers.reduce(0)  return $0 + $1  / numbers.count
print(avg) // 3

宾果!我想我记得在某处读过(不记得它是否与 Swift、javascript 或一般编程数学有关),这与将总和除以长度产生浮点数 / 双精度数的事实有关。 (1 + 2) / 5 = 0.6 将在总和内向下舍入到 0。不过我希望((1 + 2) + 3) / 5 = 1.2 会返回1,但它似乎也返回0

对于双精度数,无论以哪种方式计算,只要我将计数整数装箱为双精度数,计算都会按预期工作:

let numbers = [1.0,2.0,3.0,4.0,5.0]
let avg = numbers.reduce(0)  return $0 + $1 / Double(numbers.count)  
print(avg) // 3

我想我明白为什么(也许不是?)。但我想不出一个可靠的例子来证明这一点。

非常感谢任何帮助和/或解释。谢谢。

【问题讨论】:

int / int -> int: 类型必须被提升first才能进行浮点除法。 【参考方案1】:

除法不会产生双倍;你在做整数除法。

你没有收到((1 + 2) + 3 etc.) / 5

在第一种情况下,您会收到(((((0 + (1/5 = 0)) + (2/5 = 0)) + (3/5 = 0)) + (4/5 = 0)) + (5/5 = 1)) = 0 + 0 + 0 + 0 + 0 + 1 = 1

在第二种情况下,您会收到((((((0 + 1) + 2) + 3) + 4) + 5) / 5) = 15 / 5 = 3

在第三种情况下,双精度损失远小于整数,你会得到类似(((((0 + (1/5.0 = 0.2)) + (2/5.0 = 0.4)) + (3/5.0 = 0.6)) + (4/5.0 = 0.8)) + (5/5.0 = 1.0))

【讨论】:

感谢您的意见。那么,当所有输入都是 Ints 时,为什么 2 个 reduce 案例会给出不同的结果? @KyleGillen 因为int / int -> int每次减少时都会发生精度损失。 @KyleGillen 因为它们是不同的操作。 谢谢。好的,我现在可能很慢 - 但在某些时候减少的情况下,除法是 15 / 5 应该 = 3,不是吗?为什么会在这种情况下发生数据丢失? 在任何时候你都不会在第一个 reduce 中除以 15/5。在将它们添加到累加器之前,您将 1、2、3、4 和 5 中的每一个除以 5。对于前四个中的每一个,除以 5 的结果为零。【参考方案2】:

问题是您尝试使用第一段代码在数学上没有意义。

序列的平均值是整个序列的总和除以元素的数量。

reduce 为被调用的集合的每个成员调用 lambda 函数。因此,您一直在求和和除法。

【讨论】:

除法只适用于$1(注意运算符优先级),累加器的初始值为零,数学很好。 好吧,如果使用有理算术,数学会很好。如我们所见,事实并非如此。 谢谢@andre-artus。在某些时候我确实想到了,所以我假设:(1+2) / 5 = 0.6 > (0.6 + 3) / 5 = 0.72 等等,这确实解释了以 1 结尾的***用例. 但是,在使用双精度的情况下 - 为什么它会按预期工作? @KyleGillen,muhmuhten 是对的,我读它是因为你在除以总和,当你正在做的是将每个元素除以计数,然后对它们求和(有效,但不必要)。跨度> @muhmuhten,你是对的(第二次更是如此:))。我已经交换了元素和累加器(在我的脑海中)。【参考方案3】:

对于那些难以理解原始答案的人。

考虑一下。

let x = 4
let y = 3 

let answer = x/y

您希望答案是 Double,但不,它是 Int。让您得到一个不是四舍五入的 Int 的答案。您必须明确将值声明为 Double。见下文

let doubleAnswer = Double(x)/Double(y)

希望这会有所帮助。

【讨论】:

以上是关于为啥我不能在 Swift 的 reduce 中正确划分整数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能在 Swift 中使用 let in 协议?

为啥我不能在 Swift 中解码我的 JSON 文件?

为啥我不能在 Swift 3 中使用 JTAppleCalendar Pod 文件 JTAppleCell?

为啥我不能在 Swift 中调用 UIViewController 上的默认 super.init()?

为啥我不能在 Swift5 中读取推送消息数据?

Swift 3:为啥我不能在 didDeselectRowAt 中更改 cell.accessoryType 和 cell.textLabel