当消极时,迅速加倍奇怪

时间:2017-03-23 07:46:57

标签: swift function swift3 xcode8

Xcode 8.2.1,Swift 3。

import UIKit

extension Double {
    /// Linear interpolation.
    /// Converts a number in one range to its equivalent in another range.
    func interpolate(from: ClosedRange<Int>, to: ClosedRange<Int>) -> Double {
        let oldValue = self
        let offset = Double(to.lowerBound - from.lowerBound)
        let expansion = Double(to.upperBound - to.lowerBound) / Double(from.upperBound - from.lowerBound)

        print("\nvalue", oldValue)
        print("Sign", self.sign)
        print("offset", offset)
        print("expansion", expansion)
        print("oldLowerbound", Double(from.lowerBound))

        let newValue = (oldValue - Double(from.lowerBound)) * expansion + offset
        return newValue
    }
}
print( 1.0.interpolate(from: 0...10, to: 50...70)) // Prints 52.0.  Correct
print(-1.0.interpolate(from: 0...10, to: 50...70)) // Prints -52.0.  Expected 48.0.
print((-1.0).interpolate(from: 0...10, to: 50...70)) // Prints 48. Correct.

当单元测试在大多数(看似)琐碎的代码中发现意外问题时,它们会为自己付出代价:

(上面的代码将在iOS游乐场中运行。)

有没有办法扩展Double以使第二个print语句按预期工作(不使用第三个print语句中的括号)?

2 个答案:

答案 0 :(得分:2)

Martin R是正确的,它是评估顺序的问题,遗憾的是(据我所知)中缀运算符(在这种情况下为-)不能指定优先级。我想出的唯一方法是制作自定义插值运算符

infix operator ~|
func ~|(lhs: Double, rhs: (from: ClosedRange<Int>, to: ClosedRange<Int>)) -> Double {
  return lhs.interpolate(from: rhs.from, to: rhs.to)
}

所以结果是:

-1.0 ~| (from: 0...10, to: 50...70) // prints 48

并且为了防止双扩展方法插值被直接调用,它可以被文件私有地封装在同一个文件中。

答案 1 :(得分:1)

这是评估顺序的问题。您的第二个表达式被评估为

-(1.0.interpolate(from: 0...10, to: 50...70)) // -52.0

即。 <{1}}上调用了interpolate(),结果被否定了。

您必须在第三个表达式中设置明确的括号,以便在1.0上调用interpolate()

-1.0