美文网首页
各种数值类型之间的相互转换

各种数值类型之间的相互转换

作者: 曹来东 | 来源:发表于2018-09-20 16:36 被阅读25次
    // 声明了一个Int类型对象n,
    // 并为它初始化为1000
    let n = 1000
    // 注意!
    // 如果直接写:let c = Int8(n)
    // 将会引发运行时异常!
    // 由于1000已经超出了Int8能表示的范围。
    // 所以我们这里先通过按位与操作,
    // 将1000值压缩到[0, 127]之间。
    let c = Int8(n & 127)
    

    这里需要特别留意的是,高精度数据转换为低精度数据之前,必须确保高精度数据的值的范围已经在目标精度的范围内,否则在运行时转换将会引发异常。倘若不在目标精度范围内,我们可以通过按位与操作对源数值进行压缩。
    此外,Swift中的每种数值类型以及布尔类型还提供了一个可供 NSNumber 类型作为输入参数的构造方法。该构造方法可以通过 NSNumber 对整数或浮点数进行封装,然后内部采取高位截断或符号位扩充的形式转换为目标数据类型。而这种数据转换与大部分主流环境下的C语言正好可以兼容。

    // 声明一个Int类型常量n,
    // 用1000对它初始化
    let n = 1000
    
    // 通过NSNumber进行转换,
    // 其过程就类似于C语言中的类型转换。
    // 这里是将Int类型直接截断高位,
    // 仅保留低8位,最后取8位补码作为最终数值。
    // 输出:c = -24
    print("c = \(c)")
    
    // 上述转换过程算法如下所示:
    c = { () -> Int8 in
    var tmp = n & 0xff
    if tmp > 127 {
    tmp -= 256
    }  
    return Int8(tmp)
    }()
    // 将Int8类型转换为UInt16类型,
    // 这里对Int8的二进制补码形式做高位符号位扩充
    let a = UInt16(truncating: NSNumber(value: c))
     
    // 输出:a = 65512
    print("a = \(a)")
     
    // 通过NSNumber也可以将一个整数转换为布尔类型对象。
    // 这同样也类似于C语言中的转换过程。
    var b = Bool(truncating: NSNumber(value: c))
    // 上述转换其实等价于:
    b = c != 0 ? true : false
     
    print("b = \(b)")
    

    整数与浮点数可用的计算操作符

    • 整数与浮点数可用的算术计算操作符有:加法(+)、减法(-)、乘法(*)、除法(/)以及取相反数操作(-)和取正数操作符(+)。这里各位要注意的是,加法和减法操作符属于双目操作符,它需要两个操作数;而取相反数操作符和取正数操作符则都是单目操作符,它们只需要一个操作数。此外,整数类型对象还能使用求模操作(%),而浮点数则不能作为求模操作的操作数。
    • 整数与浮点数还都能使用比较操作符:大于(>)、大于等于(>=)、小于(<)、小于等于(<=)、等于(==)以及不等于(!=)。比较操作符的结果类型都是布尔类型。如果比较操作符的左操作数与右操作数的比较关系成立,那么结果为真(true);否则结果为假(false)。
    • 整数类型对象还能使用按位操作:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)。
      整数类型对象还能使用移位操作:左移(<<)、右移(>>)。这里各位要注意的是右移操作。如果右移操作的左操作数是一个带符号整数,那么使用的是扩充符号位的算术右移;如果左操作数是一个无符号整数,那么使用的是高位直接用零填充的逻辑右移。此外,必须要注意的是,移位操作的右操作数必须是一个非负整数.
    var a: Int8 = -1
    a >>= 7 // a的结果为-1
     
    var b: UInt8 = 255
    b >>= 7 // b的结果为1
     
    // 因为8正好是算术左移左操作数的位宽大小,
    // 因此a的值为0
    a <<= 8
     
    // 因为8正好是逻辑右移左操作数的位宽大小,
    // 因此b的值为0
    b >>= 8
    

    C语言中关系操作符(即Swift中的比较操作符)的优先级比按位操作符要高,这是因为C语言中没有显式的布尔类型,一个关系操作符的结果也是一个整型值。而在Swift编程语言中就不是如此了,Swift编程语言中,移位操作符、按位操作符的优先级都比条件操作符要高。其实这种安排对于程序员而言更为自然。

    let a = 1, b = 2
    var result = a & b < a | b
    // 输出:result = true
    print("result = \(result)")
     
    result = a << 2 > b << 1
     
    // 输出:result = false
    print("result = \(result)")
    

    布尔类型对象可以使用逻辑操作符:并且(&&)、或者(||)以及非(!)。如果一个逻辑表达式中存在多个逻辑操作符,那么其操作优先级为:! > && > ||。
    对于并且(&&)操作,如果其左操作数表达式的值为假,那么直接返回结果 false,而不会执行其右操作数的表达式。对于或者(||)操作,如果其左操作表达式的值为真,那么也不会再去计算右操作数表达式,而直接返回 true

    let a = true
    let b = false
    var c = !b // 结果为true
    c = a && b // 结果为false
    c = a || b // 结果为true
     
    /// foo1的功能为打印foo1,
    /// 且返回0
    func foo1() -> Int {
    print("foo1")
    return 0
    }
     
    /// foo2的功能为打印foo2,
    /// 且返回1
    func foo2() -> Int {
    print("foo2")
    return 1
    }
     
    // 这里当&&的左操作数表达式的值为false时就不再继续执行&&的右操作数表达式了,
    // 所以只输出foo1,并且bool的值为false
    var bool = foo1() > 1 && foo2() < 0
    print("bool = \(bool)")
     
    // 这里当||的左操作数表达式的值为false时,
    // 还需要继续判断||的右操作数表达式的值,
    // 所以这里会打印出foo1和foo2,
    // 这里的bool仍然为false
    bool = foo1() > 1 || foo2() < 0
    print("bool = \(bool)")
     
    // 当||的左操作数表达式的值为true时,
    // 则不会再去计算||右操作数表达式。
    // 所以这里只会打印出foo1,
    // 这里的bool为true
    bool = foo1() < 1 || foo2() > 0
    print("bool = \(bool)")
     
    // 这里用于判别&&与||操作的优先级,
    // 这里先执行||左边的表达式:foo1() > 1 && foo2() < 0,
    // 然后执行||右边的表达式:foo2() < 3 && foo1() < 10,
    // 最后bool的值为true
    bool = foo1() > 1 && foo2() < 0 || foo2() < 3 && foo1() < 10
    print("bool = \(bool)")
    

    Swift编程语言中的赋值操作符(=)以及与赋值操作相关的 +=、-=、*=、/= 等操作符与C语言的返回类型有所不同!C语言中,这些操作符表达式的返回类型为这些操作符的左操作数类型;而在Swift中则是返回 Void 类型。

    溢出计算操作

    如果对一个整数做一般算术计算时发生了溢出,那么程序会在运行时抛出异常。Swift中包含了允许计算时发生溢出的操作符,以允许开发者对整数做算术计算时发生结果溢出,而不引发异常。这些操作符包括:可溢出的加法(&+)、可溢出的减法(&-)以及可溢出的乘法(&*)。这些可溢出的计算操作就跟C语言的通常实现效果一样了——无论当前计算结果是多少,把高位舍去,只保留能容下当前整数对象的低位比特位,然后以补码的形式确定数值。

    let a: Int8 = 120
    let b: Int8 = 100
     
    // c的加法结果为220,类型为Int8
    // 对应于二进制: 1101 1100
    // 其补码对应的十进制数为-36
    var c = a &+ b
     
    // 此时c的减法结果为-220,
    // 对应的二进制:1 0010 0100
    // 将超过8位的最高位1去除,
    // 剩余的低8位是:0010 0100
    // 其补码对应的十进制数为36
    c = -100 &- a
     
    // 这里c的乘法结果是12000。
    // 十六进制表达为:0x2EE0
    // 将高8位去除,只保留低8位,
    // 得到:1110 0000,
    // 其补码对应的十进制数为-32
    c = a &* b
    

    以上执行过程全都正常,不会有任何异常抛出。

    相关文章

      网友评论

          本文标题:各种数值类型之间的相互转换

          本文链接:https://www.haomeiwen.com/subject/wowgnftx.html