Why Is Uint64 Max Equal -1 in Swift

Why UInt64.max / 2 + 1 represented in the memory the same as Int64 value -9 223 372 036 854 775 808 but not as -1?

Yes, in fact -1 is not represented as 1 with a sign bit, but rather as all bits set to one. This is called a "two's complement" representation, and is used in most of the modern processors.

Read more about it here:

https://en.wikipedia.org/wiki/Two%27s_complement

One of the reasons for that is that this way arithmetic operations that involve both negative and positive numbers are easier. If -1 was represented as 1 with a sign bit, and we attempted to add 1 to it in a naive way, we would get 2 with a sign bit instead of zero. With two's complement representation you can just add the numbers as if they were unsigned, and get the correct result.

Swift - UInt behaviour

Apparently this is just a bug in swift playground and according to @Anton, printing the variables shows the correct value.

Sample Image

Weird UInt64 behavior in Swift

That looks like a bug to me.

let p1 = pow(Double(2), Double(64))

is greater than UInt64.max, therefore

let x1 = UInt64(p1)

should crash (or perhaps return UInt64.max as an approximation).

The "next smaller" floating point double variable

let p2 = nextafter(p1, 0.0)
let x2 = UInt64(p2)
// 18446744073709549568

is converted correctly, and the "next larger" floating point double variable
fails correctly to convert

let p3 = nextafter(p1, DBL_MAX)
let x3 = UInt64(p3)
// fatal error: floating point value can not be converted to UInt64
// because it is greater than UInt64.max

Unable to convert UInt64 to hexadecimal?

I've no idea what PRIx64 is. I did this:

uint64_t t = 586512487604551679;
NSString* s = [NSString stringWithFormat:@"%llx", t];
NSLog(@"%@", s); // 823b5ffffffffff

and

let t : UInt64 = 586512487604551679
let s = String(t, radix:16)
print(s) // 823b5ffffffffff

How to find out the max value for Int in Swift

“You can access the minimum and maximum values of each integer type with its min and max properties:

let minValue = UInt8.min  // minValue is equal to 0, and is of type UInt8
let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8

The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type.”

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/in/jEUH0.

How to convert NSDecimalNumber to byte array if NSDecimalNumber is bigger than Uint64?

The problem is obviously the use of uint64Value, which obviously cannot represent any value greater than UInt64.max, and your example, 59,785,897,542,892,656,787,456, is larger than that.

If you want to grab the byte representations of the 128 bit mantissa, you can use _mantissa tuple of UInt16 words of Decimal, and convert them to bytes if you want. E.g.

extension Decimal {
var byteArray: [UInt8] {
return [_mantissa.0,
_mantissa.1,
_mantissa.2,
_mantissa.3,
_mantissa.4,
_mantissa.5,
_mantissa.6,
_mantissa.7]
.flatMap { [UInt8($0 & 0xff), UInt8($0 >> 8)] }
}
}

And

if let foo = Decimal(string: "59785897542892656787456") {
print(foo.byteArray)
}

Returning:

[0, 0, 0, 0, 0, 0, 0, 0, 169, 12, 0, 0, 0, 0, 0, 0]

This, admittedly, only defers the problem, breaking the 64-bit limit of your uint64Value approach, but is still constrained to the inherent 128-bit limit of NSDecimalNumber/Decimal. To capture numbers greater than 128 bits, you'd need a completely different representation.


NB: This also assumes that the exponent is 0. If, however, you had some large number, e.g. 4.2e101 (4.2 * 10101), the exponent will be 100 and the mantissa will simply be 42, which I bet is probably not what you want in your byte array. Then again, this is an example of a number that is too large to represent as a single 128 bit integer, anyway:

if let foo = Decimal(string: "4.2e101") {
print(foo.byteArray)
print(foo.exponent)
}

Yielding:

[42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

100

How to find max value for Double and Float in Swift

As of Swift 3+, you should use:

CGFloat.greatestFiniteMagnitude
Double.greatestFiniteMagnitude
Float.greatestFiniteMagnitude


Related Topics



Leave a reply



Submit