How to create a function accepting any type of Int or Uint in swift
(and calculating number of bits needs regarding param type)
String has constructors
init<T : _SignedIntegerType>(_ v: T, radix: Int, uppercase: Bool = default)
init<T : _UnsignedIntegerType>(_ v: T, radix: Int, uppercase: Bool = default)
which can be used here:
let num = 100
let str = String(num, radix: 2)
print(str)
// Output: 1100100
Here's a little shorter version. It doesn't add extra leading zeroes though:
func bitRep<T: IntegerArithmeticType>(value: T) -> String {
var n: IntMax = value.toIntMax()
var rep = ""
while(n > 0){
rep += "\(n % 2)"
n = n / 2;
}
return rep
}
let binStr:Int->String = {a in return String(a, radix: 2)}
binStr(7) // "111"
Here's a function using Generics in order to accept any type of Int or Uint without param conversion needs.
1- The function needs to constraint a value type conforming to "ToInt" protocol
in order to offer an unique method to convert self type to Int
2- The function calculates length bit needs regarding param type
3- The function insert space every 8 digits to offer legibility
protocol ToInt { func toInt() -> Int }
extension UInt: ToInt { func toInt() -> Int { return Int(self) } }
extension Int8: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt8: ToInt { func toInt() -> Int { return Int(self) } }
extension Int16: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt16: ToInt { func toInt() -> Int { return Int(self) } }
extension Int32: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt32: ToInt { func toInt() -> Int { return Int(self) } }
extension Int64: ToInt { func toInt() -> Int { return Int(self) } }
extension UInt64: ToInt { func toInt() -> Int { return Int(self) } }
func bitRep<T:ToInt>(value: T) -> String {
var size: Int
switch value {
case is Int8, is UInt8: size = 7
case is Int16, is UInt16: size = 15
case is Int32, is UInt32: size = 31
case is Int64, is UInt64: size = 63
default : size = 63
}
var n = value.toInt()
var rep = ""
for (var c = size; c >= 0; c--) {
var k = n >> c
if (k & 1) == 1 { rep += "1" } else { rep += "0" }
if c%8 == 0 && c != 0 { rep += " " }
}
return rep
}
Some examples:
let b1: UInt8 = 0b00000000
bitRep(b1)
// > "00000000"
let c1: UInt16 = 0b00000000_10000101
bitRep(c1)
// > "00000000 10000101"
let e1: UInt64 = 0b00000000_00000000_00000000_00000001
bitRep(e1)
// > "00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001"
and so on!
(algo inspired from this thread: Turning an integer to its binary representation using C?)
Related
I'm creating some utility class stores numeric values(Int, Float, Double etc...).
It has minimum and maximum value, too.
I need convert a value to percent.
So I write the class as below on Playground:
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 !!!
When call s.percent(value: s.datas[0]), it crashed.
How can I write percent() function?
Not every SignedNumeric can be converted to a Float. Recall that to be a SignedNumeric, you need to be able to:
be negative and positive
be multiplied
be added and subtracted
have a magnitude that is Comparable and Numeric
can be converted from an integer
The last 4 requirements are all inherited from Numeric. We can easily build our own type that can do all those things. Here's a contrived example:
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
}
How on earth is <insert whoever is doing the conversion here> going to know that, to convert MyNumber to Float, it has to do Float(aMyNumber.secret.count)!? Not to mention that secret is private.
On the other hand, Float.init does know how to convert BinaryFloatingPoints and BinaryIntegers to Float, because those protocols define the necessary properties such that Float.init can understand how they are represented. For example, BinaryIntegers are represented by words, which is a RandomAccessCollection of UInts, indexed by Ints.
I suggest that you only add the percent method to types of Series where it actually makes sense:
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, it would make sense for any T : FloatingPoint, not just 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
}
}
Since FloatingPoint supports division too, you don't need to convert to Float!
thank you very much!
I added two extensions:
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
}
}
And now I can use percent() with Int, Float, Int16... !
Goal
I want to extend basic types like Int, Double, Float... with more flexible properties and make it presentable in a chart on my app. For example, I made a chart draw that is suitable only for displaying Intbut cannot really display Float. I want to make sure when I pass arguments to this view it will display correctly.
Solution
So I made a protocol (for this example made it like this):
protocol SimplyChartable {
static func max(_ dataSet: [SimplyChartable]) -> SimplyChartable
}
And then make an extension for some types:
extension Int: SimplyChartable { }
extension Double: SimplyChartable { }
extension Float: SimplyChartable { }
and so on ...
Problem
This will be all numeric types, and whenever I pass it as numeric types to a func I need to extend all extension like this:
public static func max(_ dataSet: [SimplyChartable]) -> SimplyChartable {
return (dataSet as? [Int])?.max() ?? 0
}
But for Double func will be identical.
So for min I will end up with similar function, the same for divide, adding , some other math... There is a way to write it once and reuse for every type that extends this protocol?
I found out that:
let dataType = type(of: maxValue) /* where `maxValue` is SimplyChartable*/
Will return original type as rawValue. But output of a method type(of is a Metatype and I cannot return it from function and then add two values of this type. So for example this code will not work:
let val1 = SimplyChartable(4)
let val2 = SimplyChartable(2)
let sum = val1 + val2
And how to make it work not ending up with 3 functions like this:
let val1 = SimplyChartable(4)
let val2 = SimplyChartable(2)
let sum = (val1 as! Int) + (val2 as! Int)
Since they all numeric types why don't you use Comparable?
extension SimplyChartable {
static func max<T: Comparable>(dataSet: [T]) -> T? {
return dataSet.max()
}
static func min<T: Comparable>(dataSet: [T]) -> T? {
return dataSet.min()
}
}
extension Int: SimplyChartable { }
extension Double: SimplyChartable { }
Double.max([1.2, 1.1, 1.3]) // 1.3
Int.min([12, 11, 13]) // 11
Just my two cents worth...
This isn't exactly what you've asked for, since it doesn't let you call a static function directly from a protocol metatype. But since that, AFAIK, isn't possible in Swift currently, perhaps this would be the next best thing?
extension Sequence where Element == SimplyChartable {
func max() -> SimplyChartable {
// put your implementation here
}
}
You can then call this by just:
let arr: [SimplyChartable] = ...
let theMax = arr.max()
For your situation, it's much better to use an Array extension rather than a protocol with an array parameter.
To handle each possible type of array i.e [Int], [Double] or [Float], create a wrapper enum with associated types as follows:
public enum SimplyChartableType {
case int(Int)
case float(Float)
case double(Double)
func getValue() -> NSNumber {
switch self {
case .int(let int):
return NSNumber(value: int)
case .float(let float):
return NSNumber(value: float)
case .double(let double):
return NSNumber(value: double)
}
}
init(int: Int) {
self = SimplyChartableType.int(int)
}
init(float: Float) {
self = SimplyChartableType.float(float)
}
init(double: Double) {
self = SimplyChartableType.double(double)
}
}
You can extend Array as follows:
extension Array where Element == SimplyChartableType {
func max() -> SimplyChartableType {
switch self[0] {
case .int(_):
let arr = self.map({ $0.getValue().intValue })
return SimplyChartableType(int: arr.max()!)
case .double(_):
let arr = self.map({ $0.getValue().doubleValue })
return SimplyChartableType(double: arr.max()!)
case .float(_):
let arr = self.map({ $0.getValue().floatValue })
return SimplyChartableType(float: arr.max()!)
}
}
}
Example usage is:
var array = [SimplyChartableType.double(3),SimplyChartableType.double(2),SimplyChartableType.double(4)]
var max = array.max()
And now it's a lot easier to operate on Int, Double or Float together with:
extension SimplyChartableType: SimplyChartable {
//insert functions here
static func randomFunction() -> SimplyChartableType {
//perform logic here
}
}
The above snippet is good if you need a different functionality which operates on non-Collection types.
This doesn't answer your specific question, unfortunately. Perhaps a work around to use a free function and casting.
import UIKit
protocol SimplyChartable {
func chartableValue() -> Double
}
extension Int: SimplyChartable {
func chartableValue() -> Double {
return Double(self) ?? 0
}
}
extension Double: SimplyChartable {
func chartableValue() -> Double {
return self
}
}
extension Float: SimplyChartable {
func chartableValue() -> Double {
return Double(self) ?? 0
}
}
func maxOfSimplyChartables(_ dataSet: [SimplyChartable]) -> SimplyChartable {
return dataSet.max(by: { (lhs, rhs) -> Bool in
return lhs.chartableValue() < rhs.chartableValue()
}) ?? 0
}
let chartableItem1: SimplyChartable = 1255555.4
let chartableItem2: SimplyChartable = 24422
let chartableItem3: SimplyChartable = 35555
let simplyChartableValues = [chartableItem1, chartableItem2, chartableItem3]
maxOfSimplyChartables(simplyChartableValues)
i saw an example on "Pro swift" book.
it overloaded the operator, the first parameter "lhs" is a function that takes T -> U.
but "generateRandomNumber" function is Int -> Int
How can it work on >>> operator?
how does it work?
thanks.
import Foundation
infix operator >>> { associativity left }
func >>> <T, U, V>(lhs: T -> U, rhs: U -> V) -> T -> V {
return { rhs(lhs($0)) }
}
func generateRandomNumber(max: Int) -> Int {
let number = Int(arc4random_uniform(UInt32(max)))
print("Using number: \(number)")
return number
}
func calculateFactors(number: Int) -> [Int] {
return (1...number).filter { number % $0 == 0 }
}
func reduceToString(numbers: [Int]) -> String {
return numbers.reduce("Factors: ") { $0 + String($1) + " " }
}
let combined = generateRandomNumber >>> calculateFactors >>>
reduceToString
print(combined(100))
see the documentation about generics.
let combined = generateRandomNumber >>> calculateFactors >>> reduceToString
print(generateRandomNumber.dynamicType)
print(calculateFactors.dynamicType)
print(reduceToString.dynamicType)
print(combined.dynamicType)
/*
Int -> Int
Int -> Array<Int>
Array<Int> -> String
Int -> String
*/
I created this infix operator ^^ as a substitute to using the pow function:
infix operator ^^ { associativity left precedence 155 }
func ^^ <T: IntegerLiteralConvertible>(left: T, right: T) -> T {
return pow(left as Double, right as Double)
}
I used the IntegerLiteralConvertible protocol as a type constraint for the generics left and right, because from my understanding this diagramm shows, that it basically includes all number types.
In order to use the pow function I have to downcast left and right to Double though, which I did using the as operator. It's not the safest approach, but that's besides the point.
When implementing the function this way swift tells me:
<stdin>:4:12: error: cannot invoke 'pow' with an argument list of type '(Double, Double)'
return pow(left as Double, right as Double)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now as far as I know pow takes two Doubles as parameters, so why is it complaining about this?
why is it complaining about this?
Because pow returns Double. And Double is not identical to T. The error message is misleading, but it means "Cannot find pow that accepts (Double, Double) and returns T type"
I think you are misunderstanding "cast" in Swift. In Swift as does not convert numeric types.
let intVal:Int = 12
let doubleVal:Double = intVal as Double
// ^ [!] error: 'Int' is not convertible to 'Double'
And If the type of operand is not predictable at compile time, invalid casting causes runtime error:
func foo<T: IntegerLiteralConvertible>(x: T) {
x as Double // <-- Execution was interrupted
}
foo(12 as Int)
Instead, we must explicitly "convert" them. see the document: Numeric Type Conversion
let intVal:Int = 12
let doubleVal:Double = Double(intVal)
This works only because Double has init(_ v: Int) initializer. The following code does not compile:
func foo<T: IntegerLiteralConvertible>(x: T) {
Double(x)
// ^~~~~~~~~ [!] error: cannot invoke 'init' with an argument of type 'T'
}
Because Double does not have init<T:IntegerLiteralConvertible>(_ val:T) initializer.
So, if you want to use pow(), you must convert T to Double for arguments, and convert Double to T for returning value. And there is no simple solution for that.
Thanks #Martin R. This comes from the only question I have posted so far at S.O.
import Cocoa
Protocols
protocol Fraction { init(_ value:Double) ; var asDouble : Double { get } }
protocol Text { init(_ value:String) ; var asString : String { get } }
Extensions
extension String : Text { var asString : String { return self } }
extension Double : Fraction { var asDouble : Double { return self } }
extension Float : Fraction { var asDouble : Double { return Double(self) } }
extension CGFloat : Fraction { var asDouble : Double { return Double(self) } }
infix operator ^^
infix operator ^^ { associativity left precedence 170 }
func ^^<T:IntegerType, U:IntegerType> (var base:T, var power:U) -> T {
if power < 0 { return 0 }
var result: T = 1
if power > 0 {
if power % 2 == 1 { result *= base }
power /= 2
}
while power > 0 {
base *= base
if power % 2 == 1 { result *= base }
power /= 2
}
return result
}
func ^^<T:Fraction, U:Fraction> (base: T, power: U) -> T {
return T(pow(base.asDouble, power.asDouble))
}
func ^^<T:Text, U:IntegerType> (base:T, var power:U) -> T {
if power <= 0 { return "" as T }
if power == 1 { return base as T }
return power > 1 ? {var result = ""; for x in 1...power { result+=base.asString };return result as T}() : "" as T
}
func ^^<T:Text, U:Text> (base:T, var power:U) -> T {
return "" as T
}
testing
println(1 ^^ -1) // "0" Int
println(1 ^^ 0) // "1" Int
println(1 ^^ 1) // "1" Int
println(1 ^^ 2) // "1" Int
println(2 ^^ -1) // "0" Int
println(2 ^^ 0) // "1" Int
println(2 ^^ 1) // "2" Int
println(2 ^^ 2) // "4" Int
println(2 ^^ 8) // "256" Int
println(2 ^^ 16) // "65536" Int
println(2 ^^ 32) // "4294967296" Int
println(2 ^^ 62) // "4611686018427387904"
println(UInt(2) ^^ 8) // "256" UInt
println(UInt64(2) ^^ 8) // "256" UInt64
I have created a ^^ operator in Swift. How do I make it work with Integers and Doubles like all other operators?
infix operator ^^ { }
func ^^ (number:Int, power: Int) -> Int {
var result = power > 0 ? number : 0
if power > 1 { for x in 1..<power { result *= number } }
return result
}
Here is a more type-safe implementation, using operator overloading. For integer types,
you can define ^^ as
infix operator ^^ { associativity left precedence 170 }
func ^^<T : IntegerType, U : IntegerType> (base: T, var power: U) -> T {
if power < 0 { return 0 }
var result : T = 1
var square : T = base
if power > 0 {
if power % 2 == 1 { result *= square }
power /= 2
}
while power > 0 {
square *= square
if power % 2 == 1 { result *= square }
power /= 2
}
return result
}
(I have chosen a more efficient variant called "exponentiation by repeated squaring and multiplication".)
For floating point types, define a protocol the covers all types that can be
converted from and to Double:
protocol DoubleConvertible {
init(_ value: Double)
var doubleValue : Double { get }
}
and make Float, Double and CGFloat conform to that protocol:
extension Double : DoubleConvertible {
var doubleValue : Double { return self }
}
extension Float : DoubleConvertible {
var doubleValue : Double { return Double(self) }
}
extension CGFloat : DoubleConvertible {
var doubleValue : Double { return Double(self) }
}
Now the floating point exponentiation can simply be defined as
func ^^<T : DoubleConvertible, U:DoubleConvertible> (base: T, power: U) -> T {
return T(pow(base.doubleValue, power.doubleValue))
}
Examples:
let x1 = 2^^3 // Int
let x2 = UInt64(2)^^3 // UInt64
let x3 = 2.0 ^^ 3 // Double
let x4 = Float(2.0) ^^ 3 // Float
let x5 = "a" ^^ "b" // Compiler error
Update for Swift 4:
IntegerType has become BinaryInteger (SE-0104 Protocol-oriented integers) and
the syntax for declaring operators has changed
(SE-0077 Improved operator declarations.)
Here is an implementation for all integer and floating point
bases with Int exponents:
precedencegroup ExponentiationPrecedence { associativity: right higherThan: MultiplicationPrecedence }
infix operator ^^: ExponentiationPrecedence
func ^^<T : BinaryInteger>(base: T, power: Int) -> T {
if power < 0 { return 0 }
var power = power
var result: T = 1
var square = base
if power > 0 {
if power % 2 == 1 { result *= square }
power /= 2
}
while power > 0 {
square *= square
if power % 2 == 1 { result *= square }
power /= 2
}
return result
}
func ^^(base: Float, power: Int) -> Float {
return pow(base, Float(power))
}
func ^^(base: Double, power: Int) -> Double {
return pow(base, Double(power))
}
func ^^(base: CGFloat, power: Int) -> CGFloat {
return pow(base, CGFloat(power))
}
Examples:
let x1 = 2^^3 // Int
let x2 = UInt64(2)^^3 // UInt64
let x3 = 2.0 ^^ -3 // Double
let x4 = Float(2.0) ^^ 3 // Float
// let x6 = "a" ^^ 5 // Compiler error
See SE-0104 Protocol-oriented integers
about the new protocol hierarchy introduced in Swift 4.