Swift - 在最小值和最大值之间缩放数字

6

如何将一个数字缩放到指定的范围内? 例如,如果我有:

Input_min = 10.1;
Input_max = 750.0;

Range_min = 0.0;
Range_max = 350.0;

example Input_n = 503.9;

如何使用Swift将任何数字缩放到范围最小值和最大值之间?


1
你是在询问数学公式,还是Swift实现,还是两者都需要? - Martin R
嗨,马丁,我需要这个数学公式。 - SNos
这是简单的插值。 - tadman
3个回答

7

edit/update: Xcode 11.5 • Swift 5.2

extension FloatingPoint {
    func converting(from input: ClosedRange<Self>, to output: ClosedRange<Self>) -> Self {
        let x = (output.upperBound - output.lowerBound) * (self - input.lowerBound)
        let y = (input.upperBound - input.lowerBound)
        return x / y + output.lowerBound
    }
}

extension BinaryInteger {
    func converting(from input: ClosedRange<Self>, to output: ClosedRange<Self>) -> Self {
        let x = (output.upperBound - output.lowerBound) * (self - input.lowerBound)
        let y = (input.upperBound - input.lowerBound)
        return x / y + output.lowerBound
    }
}

let integer = 380
let result = integer.converting(from: 10...750, to: 100...350) // 225

let double = 750.0
let result = double.converting(from: 10.1...750.0, to: 0...350) // 350

6

下面是兼容Swift 3的版本,同时支持泛型(为了不仅局限于Double类型而限制Rescale)。

struct Rescale<Type : BinaryFloatingPoint> {
    typealias RescaleDomain = (lowerBound: Type, upperBound: Type)

    var fromDomain: RescaleDomain
    var toDomain: RescaleDomain

    init(from: RescaleDomain, to: RescaleDomain) {
        self.fromDomain = from
        self.toDomain = to
    }

    func interpolate(_ x: Type ) -> Type {
        return self.toDomain.lowerBound * (1 - x) + self.toDomain.upperBound * x;
    }

    func uninterpolate(_ x: Type) -> Type {
        let b = (self.fromDomain.upperBound - self.fromDomain.lowerBound) != 0 ? self.fromDomain.upperBound - self.fromDomain.lowerBound : 1 / self.fromDomain.upperBound;
        return (x - self.fromDomain.lowerBound) / b
    }

    func rescale(_ x: Type )  -> Type {
        return interpolate( uninterpolate(x) )
    }
}

例如:

Rescale(from: (15, 85), to: (0, 100)).rescale(85)

2

我从这里的答案翻译成了Swift,基于D3库

struct Rescale {
var range0: Double, range1: Double, domain0: Double, domain1: Double

init( domain0: Double, domain1: Double, range0: Double, range1: Double ) {
    self.range0 = range0
    self.range1 = range1
    self.domain0 = domain0
    self.domain1 = domain1
}

func interpolate( x: Double ) -> Double {
    return range0 * (1 - x) + range1 * x;
}

func uninterpolate( x: Double) -> Double {
    let b: Double = (domain1 - domain0) != 0 ? domain1 - domain0 : 1 / domain1;
    return (x - domain0) / b
}

func rescale( x: Double )  -> Double {
    return interpolate( uninterpolate(x) )
}
}

使用方法:

let scaleUp = Rescale( domain0: 15, domain1: 85, range0: 0, range1: 100 )
let scaleDown = Rescale( domain0: 0, domain1: 100, range0: 15, range1: 85 )
// scales it to 0 - 100 from the input range 15 - 85
let scaledValue = scaleUp.rescale( 85 ) // = 100
// or the other way...
let scaledValue = scaleDown.rescale( 100 ) // = 85

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