Mainly semantics. We could technically use Int instead of having a Bool type (just using 1 and 0). We don’t do that since Int and Bool have intrinsically different meanings in code.
What I am saying is that parameters that take the range 0 to 1 typically have a fundamentally different meaning (or at least a different way of thinking about them) than Doubles. It would be nice to be able to see that distinction when using APIs. With both this and the Angle type, I am pointing out areas where, due to historical reasons in C, we have conflated a bunch of types which have different behavior, and then just expect programmers to be conscientious enough to use them correctly in each case. These types/numbers all have a different forms of dimensionality. I’d like to discuss that before we lock everything down. Thanks, Jon > On Jan 13, 2018, at 9:18 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote: > > As Erica mentioned about Angle, this seems to be a perfect fit for an > appropriately focused third-party library, but I'm not sure I appreciate why > this should be part of the standard library. In large part, you seem to have > reinvented a decimal type, which is already available in the form of > Foundation.Decimal on all supported platforms. > > On Sat, Jan 13, 2018 at 9:07 PM, Jonathan Hull via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: > Here is the code I use for percentage myself. (I incorrectly said I use a > UInt64… I use a UInt32): > > ///Represents a percentage with the precision of millionths of 1 (i.e. 4 > decimal places: XX.XXXX%). The value is always positive (or zero), but may be > greater than 100% > struct Percentage { > fileprivate(set) var millionths:UInt32 > > fileprivate init(storage:UInt32){ > millionths = storage > } > > static var quarter = Percentage(storage: 250_000) > static var half = Percentage(storage: 500_000) > static var threeQuarters = Percentage(storage: 750_000) > static var full = Percentage(storage: 1_000_000) > > init(millionths:Int) { > self.millionths = UInt32(millionths) > } > > init(_ double:Double, range:ClosedRange<Double> = 0...1) { > if range == 0...1 { > self.millionths = UInt32(max(double * 1_000_000, 0)) > }else if range == 0...100{ > self.millionths = UInt32(max(double * 10_000, 0)) > }else{ > self.millionths = UInt32(max((double - > range.lowerBound)/(range.upperBound - range.lowerBound),0)) > } > } > > init(_ num:Num, range:ClosedRange<Num> = 0...1) { > if range == 0...1 { > self.millionths = UInt32(max(num * 1_000_000, 0).integerValue) > }else if range == 0...100{ > self.millionths = UInt32(max(num * 10_000, 0).integerValue) > }else{ > self.millionths = UInt32(max((num - > range.lowerBound)/(range.upperBound - range.lowerBound),0).integerValue) > } > } > > init(_ decimal:Decimal, range:ClosedRange<Decimal> = 0...1) { > if range == 0...1 { > self.millionths = NSDecimalNumber(decimal: max(decimal * > 1_000_000, 0)).uint32Value > }else if range == 0...100{ > self.millionths = NSDecimalNumber(decimal: max(decimal * 10_000, > 0)).uint32Value > }else{ > let shifted = max((decimal - range.lowerBound)/(range.upperBound > - range.lowerBound),0) > self.millionths = NSDecimalNumber(decimal: shifted).uint32Value > } > } > > init(hundredths:Int) { > self.millionths = UInt32(max(hundredths * 10_000, 0)) > } > > init(thousandths:Int) { > self.millionths = UInt32(max(thousandths * 1_000, 0)) > } > > var isFull:Bool { > return self.millionths >= 1_000_000 > } > > var doubleValue:Double{ > return Double(self.millionths)/1_000_000 > } > > var cgfloatValue:CGFloat{ > return CGFloat(self.millionths)/1_000_000 > } > > var decimalValue:Decimal { > return Decimal(self.millionths)/1_000_000 > } > > var numValue:Num { > return Num(numerator: Int32(self.millionths), denominator: 1_000_000) > } > > var hundredths:Int { > return Int(self.millionths/10_000) > } > > var thousandths:Int { > return Int(self.millionths/1_000) > } > > var tenThousandths:Int { > return Int(self.millionths/100) > } > > func map(to range:ClosedRange<Num>) -> Num { > return self.numValue * (range.upperBound - range.lowerBound) + > range.lowerBound > } > > mutating func clip() { > if self.millionths > 1_000_000 { > self.millionths = 1_000_000 > } > } > > func clipped()->Percentage { > if self.millionths > 1_000_000 { > return Percentage.full > } > return self > } > > > } > > extension Percentage:CustomStringConvertible { > var description: String { > let num = self.numValue * 100 > if num.isInteger{ > return "\(num)%" > } > return "\(num.decimalValue)%" > } > } > > extension Percentage:ExpressibleByIntegerLiteral { > init(integerLiteral value: IntegerLiteralType) { > self.millionths = UInt32(max(value * 10_000, 0)) > } > } > > extension Percentage:Hashable { > var hashValue: Int { > return self.millionths.hashValue > } > > static func == (lhs:Percentage, rhs:Percentage)->Bool { > return lhs.millionths == rhs.millionths > } > } > > extension Percentage:Comparable { > static func < (lhs:Percentage, rhs:Percentage) -> Bool { > return lhs.millionths < rhs.millionths > } > } > > extension Percentage { > static func + (lhs:Percentage, rhs:Percentage)->Percentage { > return Percentage(storage: lhs.millionths + rhs.millionths) > } > > static func - (lhs:Percentage, rhs:Percentage)->Percentage { > if rhs > lhs {return 0} > return Percentage(storage: lhs.millionths - rhs.millionths) > } > > static func * (lhs:Percentage, rhs:Double)->Double { > return lhs.doubleValue * rhs > } > > static func * (lhs:Double, rhs:Percentage)->Double { > return lhs * rhs.doubleValue > } > > static func * (lhs:Percentage, rhs:CGFloat)->CGFloat { > return lhs.cgfloatValue * rhs > } > > static func * (lhs:CGFloat, rhs:Percentage)->CGFloat { > return lhs * rhs.cgfloatValue > } > > static func * (lhs:Percentage, rhs:Num)->Num { > return lhs.numValue * rhs > } > > static func * (lhs:Num, rhs:Percentage)->Num { > return lhs * rhs.numValue > } > > static func * (lhs:Percentage, rhs:Percentage)->Percentage { > return Percentage(lhs.decimalValue * rhs.decimalValue) > } > > } > > > >> On Jan 13, 2018, at 6:26 PM, Jonathan Hull via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> >> Hi Evolution, >> >> I was wondering if we would consider adding a percentage type to Swift. >> This would be a type with a value between 0 & 1. >> >> I know we can and do use doubles or floats for this now, but there really is >> a semantic difference between most parameters that take a value between 0 & >> 1 and those that take any floating point value. It would be nice to have a >> type that semantically means that the value is from 0 to 1. >> >> It could even just wrap a Double for speed (in my own code I wrap a UInt64 >> for decimal accuracy… and to avoid issues around comparisons). >> >> Thanks, >> Jon >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <mailto:swift-evolution@swift.org> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution> > >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution