如何将泛型类型有符号数字转换为浮点数?



我正在创建一些实用程序类存储数值(Int,Float,Double 等...)。 它也有最小值和最大值。

我需要将值转换为百分比。

所以我在操场上写了如下课程:

import UIKit
class Series<T: SignedNumeric> {
let minValue: T
let maxValue: T
var datas: [T] = []
let range: T
init(minValue: T, maxValue: T) {
self.minValue = minValue
self.maxValue = maxValue
self.range = (maxValue - minValue)
self.datas = []
}
func percent(value: T) -> Float {
let v: Float = value as! Float
let m: Float = minValue as! Float
let r: Float = range as! Float
return (v - m) / r
}
}
let s = Series<Int>(minValue: -100, maxValue: 100)
s.datas = [20, 0, 40, -100, 100]
Float(s.datas[0] - s.minValue) / Float(s.range)
Float(s.datas[1] - s.minValue) / Float(s.range)
Float(s.datas[2] - s.minValue) / Float(s.range)
Float(s.datas[3] - s.minValue) / Float(s.range)
Float(s.datas[4] - s.minValue) / Float(s.range)
s.percent(value: s.datas[0]) // ERROR !!!

当调用 s.percent(value: s.datas[0]) 时,它崩溃了。

如何编写 percent() 函数?

并非每个SignedNumeric都可以转换为Float。回想一下,要成为SignedNumeric,您需要能够:

  • 消极和积极
  • 乘以
  • 加减
  • 具有ComparableNumeric的量级
  • 可以从整数转换

最后 4 个要求都是从Numeric继承而来的。我们可以轻松地构建自己的类型,可以完成所有这些事情。下面是一个人为的例子:

struct MyNumber: SignedNumeric, Comparable {
private var secret: [String]
private var isNegative: Bool
private var number: Int { secret.count }

static func *= (lhs: inout MyNumber, rhs: MyNumber) {
lhs = lhs * rhs
}

static func * (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
MyNumber(secret: Array(repeating: "", count: lhs.number * rhs.number), isNegative: lhs.isNegative != rhs.isNegative)
}

init(integerLiteral value: Int) {
let int = value
isNegative = int < 0
secret = Array(repeating: "", count: abs(int))
}

static func < (lhs: MyNumber, rhs: MyNumber) -> Bool {
lhs.number < rhs.number
}

init?<T>(exactly source: T) where T : BinaryInteger {
guard let int = Int(exactly: source) else {
return nil
}
self.init(integerLiteral: int)
}

var magnitude: MyNumber {
MyNumber(secret: secret, isNegative: false)
}

static func - (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
if lhs < rhs {
return -(rhs - lhs)
} else {
return MyNumber(secret: Array(repeating: "", count: lhs.number - rhs.number))
}
}

prefix static func - (operand: MyNumber) -> MyNumber {
MyNumber(secret: operand.secret, isNegative: !operand.isNegative)
}

mutating func negate() {
isNegative.toggle()
}

init(secret: [String], isNegative: Bool = false) {
self.secret = secret
self.isNegative = isNegative
}

typealias Magnitude = MyNumber

static func + (lhs: MyNumber, rhs: MyNumber) -> MyNumber {
MyNumber(secret: lhs.secret + rhs.secret)
}

typealias IntegerLiteralType = Int

}

<插入在这里进行转换的人>到底是如何知道,要将MyNumber转换为Float,它必须Float(aMyNumber.secret.count)!?更不用说secret是私人的。

另一方面,Float.init确实知道如何将BinaryFloatingPointBinaryInteger转换为Float,因为这些协议定义了必要的属性,以便Float.init可以理解它们是如何表示的。例如,BinaryIntegers 由words表示,这是UInts 的RandomAccessCollection,由Ints 索引。

我建议您仅将percent方法添加到实际有意义的Series类型中:

extension Series where T : BinaryInteger {
func percent(value: T) -> Float {
let v: Float = Float(value)
let m: Float = Float(minValue)
let r: Float = Float(range)
return (v - m) / r
}
}

IMO,这对任何T : FloatingPoint都是有意义的,而不仅仅是T : BinaryFloatingPoint

extension Series where T : FloatingPoint {
func percent(value: T) -> T {
let v = value
let m = minValue
let r = range
return (v - m) / r
}
}

由于FloatingPoint也支持除法,因此您无需转换为Float

非常感谢!

我添加了两个扩展:

extension Series where T : BinaryInteger {
func percent(value: T) -> Float {
let v: Float = Float(value)
let m: Float = Float(minValue)
let r: Float = Float(range)
return (v - m) / r
}
}
extension Series where T : FloatingPoint {
func percent(value: T) -> T {
let v = value
let m = minValue
let r = range
return (v - m) / r
}
}

现在我可以将 percent() 与 Int、Float、Int16 一起使用... !

相关内容

  • 没有找到相关文章

最新更新