Representing numbers as integers
Now that we all know what sort of integers can be found in Swift, it is time to discuss a bit about what sort of numbers can we signify utilizing these knowledge sorts.
print(Int.min)
print(Int.max)
print(UInt.min)
print(UInt.max)
print(UInt8.min)
print(UInt8.max)
print(UInt16.min)
print(UInt16.max)
print(UInt32.min)
print(UInt32.max)
print(UInt64.min)
print(UInt64.max)
print(Int8.min)
print(Int8.max)
print(Int16.min)
print(Int16.max)
print(Int32.min)
print(Int32.max)
print(Int64.min)
print(Int64.max)
So there’s a minimal and most worth for every integer kind that we will retailer in a given variable. For instance, we will not retailer the worth 69420
inside a UInt8
kind, as a result of there are merely not sufficient bits to signify this big quantity. 🤓
Let’s look at our 8 bit lengthy unsigned integer kind. 8 bit signifies that we have now actually 8 locations to retailer boolean values (ones and zeros) utilizing the binary number illustration. 0101 0110 in binary is 86 utilizing the “common” decimal quantity format. This binary quantity is a base-2 numerical system (a positional notation) with a radix of two. The quantity 86 will be interpreted as:
- 0*28+1*27+0*26+1*25+0*24 + 1*23+1*22+0*21+0*20
- 0*128+1*64+0*32+1*16 + 0*8+1*4+1*2+0*1
- 64+16+4+2
- 86
We are able to convert forwards and backwards between decimal and binary numbers, it isn’t that arduous in any respect, however let’s come again to this matter in a while. In Swift we will examine if a sort is a signed kind and we will additionally get the size of the integer kind by the bitWidth
property.
print(Int.isSigned)
print(UInt.isSigned)
print(Int.bitWidth)
print(UInt8.bitWidth)
Primarily based on this logic, now it is fairly simple that an 8 bit lengthy unsigned kind can solely retailer 255 as the utmost worth (1111 1111), since that is 128+64+32+16+8+4+2+1.
What about signed sorts? Nicely, the trick is that 1 bit from the 8 is reserved for the optimistic / damaging image. Often the primary bit represents the signal and the remaining 7 bits can retailer the precise numeric values. For instance the Int8
kind can retailer numbers from -128 til 127, because the most optimistic worth is represented as 0111 1111, 64+32+16+8+4+2+1, the place the main zero signifies that we’re speaking a couple of optimistic quantity and the remaining 7 bits are all ones.
So how the hack can we signify -128? Is not -127 (1111 1111) the minimal damaging worth? 😅
Nope, that is not how damaging binary numbers work. So as to perceive damaging integer illustration utilizing binary numbers, first we have now to introduce a brand new time period known as two’s complement, which is an easy methodology of signed quantity illustration.
Fundamental signed quantity maths
It’s comparatively straightforward so as to add two binary numbers, you simply add the bits so as with a carry, identical to you’d do addition utilizing decimal numbers. Subtraction alternatively is a bit more durable, however luckily it may be changed with an addition operation if we retailer damaging numbers in a particular manner and that is the place two’s complement is available in.
We could say that we might like so as to add two numbers:
0010 1010
(+42)0100 0101
+(+69)0110 1111
=(+111)
Now let’s add a optimistic and a damaging quantity saved utilizing two’s complement, first we have to specific -6 utilizing a signed 8 bit binary quantity format:
0000 0110
(+6)1111 1001
(one’s complement = inverted bits)1111 1010
(two’s complenet = add +1 (0000 0001) to at least one’s complement)
Now we will merely carry out an addition operation on the optimistic and damaging numbers.
0010 1010
(+42)1111 1010
+(-6)(1) 0010 0100
=(+36)
So, you may assume, what is the take care of the additional 1 at first of the 8 bit end result? Nicely, that is known as a carry bit, and in our case it will not have an effect on our remaining end result, since we have carried out a subtraction as an alternative of an addition. As you’ll be able to see the remaining 8 bit represents the optimistic quantity 36 and 42-6 is strictly 36, we will merely ignore the additional flag for now. 😅
Binary operators in Swift
Sufficient from the idea, let’s dive in with some actual world examples utilizing the UInt8
kind. Initially, we must always discuss bitwise operators in Swift. In my earlier article we have talked about Bool operators (AND, OR, NOT) and the Boolean algebra, now we will say that these features function utilizing a single bit. This time we’ll see how bitwise operators can carry out numerous transformations utilizing a number of bits. In our pattern instances it is at all times going to be 8 bit. 🤓
Bitwise NOT operator
This operator (~) inverts all bits in a quantity. We are able to use it to create one’s complement values.
let x: UInt8 = 0b00000110
let res = ~x
print(res)
print(String(res, radix: 2))
Nicely, the issue is that we’ll hold seeing decimal numbers on a regular basis when utilizing int sorts in Swift. We are able to print out the proper 1111 1001 end result, utilizing a String
worth with the bottom of two, however for some cause the inverted quantity represents 249 in accordance with our debug console. 🙃
It is because the which means of the UInt8 kind has no understanding concerning the signal bit, and the eighth bit is at all times refers back to the 28 worth. Nonetheless, in some instances e.g. whenever you do low stage programming, equivalent to constructing a NES emulator written in Swift, that is the proper knowledge kind to decide on.
The Data type from the Basis framework is taken into account to be a set of UInt8 numbers. Truly you will discover various use-cases for the UInt8 kind for those who take a deeper take a look at the prevailing frameworks & libraries. Cryptography, knowledge transfers, and many others.
Anyway, you can also make an extension to simply print out the binary illustration for any unsigned 8 bit quantity with main zeros if wanted. 0️⃣0️⃣0️⃣0️⃣ 0️⃣1️⃣1️⃣0️⃣
import Basis
fileprivate extension String
func leftPad(with character: Character, size: UInt) -> String
let maxLength = Int(size) - depend
guard maxLength > 0 else
return self
return String(repeating: String(character), depend: maxLength) + self
extension UInt8
var bin: String
String(self, radix: 2).leftPad(with: "0", size: 8)
let x: UInt8 = 0b00000110
print(String(x, radix: 2))
print(x.bin)
print((~x).bin)
let res = (~x) + 1
print(res.bin)
We nonetheless have to offer our customized logic if we need to specific signed numbers utilizing UInt8, however that is solely going to occur after we all know extra concerning the different bitwise operators.
Bitwise AND, OR, XOR operators
These operators works identical to you’d count on it from the reality tables. The AND operator returns a one if each the bits have been true, the OR operator returns a 1 if both of the bits have been true and the XOR operator solely returns a real worth if solely one of many bits have been true.
- AND
&
– 1 if each bits have been 1 - OR
|
– 1 if both of the bits have been 1 - XOR
^
– 1 if solely one of many bits have been 1
Let me present you a fast instance for every operator in Swift.
let x: UInt8 = 42
let y: UInt8 = 28
print((x & y).bin)
print((x | y).bin)
print((x ^ y).bin)
Mathematically talking, there’s not a lot cause to carry out these operations, it will not offer you a sum of the numbers or different fundamental calculation outcomes, however they’ve a unique goal.
You should utilize the bitwise AND operator to extract bits from a given quantity. For instance if you wish to retailer 8 (or much less) particular person true or false values utilizing a single UInt8 kind you should use a bitmask to extract & set given elements of the quantity. 😷
var statusFlags: UInt8 = 0b00000100
print(statusFlags & 0b00000100 == 4)
print(statusFlags & 0b00010000 == 16)
statusFlags = statusFlags & 0b11101111 | 16
print(statusFlags.bin)
statusFlags = statusFlags & 0b11111011 | 0
print(statusFlags.bin)
statusFlags = statusFlags & 0b11101111 | 0
print(statusFlags.bin)
statusFlags = statusFlags & 0b11101011 | 4
print(statusFlags.bin)
That is good, particularly for those who do not need to fiddle with 8 totally different Bool variables, however one there’s one factor that may be very inconvenient about this resolution. We at all times have to make use of the proper energy of two, in fact we may use pow, however there’s a extra elegant resolution for this situation.
Bitwise left & proper shift operators
By utilizing a bitwise shift operation you’ll be able to transfer a bit in a given quantity to left or proper. Left shift is actually a multiplication operation and proper shift is similar with a division by an element of two.
“Shifting an integer’s bits to the left by one place doubles its worth, whereas shifting it to the proper by one place halves its worth.” – swift.org
It is fairly easy, however let me present you a couple of sensible examples so you will perceive it in a bit. 😅
let meaningOfLife: UInt8 = 42
print(meaningOfLife << 1)
print(meaningOfLife << 2)
print(meaningOfLife << 3)
print(meaningOfLife >> 1)
print(meaningOfLife >> 2)
print(meaningOfLife >> 3)
print(meaningOfLife >> 4)
print(meaningOfLife >> 5)
print(meaningOfLife >> 6)
print(meaningOfLife >> 7)
As you’ll be able to see we have now to watch out with left shift operations, because the end result can overflow the 8 bit vary. If this occurs, the additional bit will simply go away and the remaining bits are going for use as a remaining end result. Proper shifting is at all times going to finish up as a zero worth. ⚠️
Now again to our standing flag instance, we will use bit shifts, to make it extra easy.
var statusFlags: UInt8 = 0b00000100
print(statusFlags & 1 << 2 == 1 << 2)
statusFlags = statusFlags & ~(1 << 2) | 0
print(statusFlags.bin)
statusFlags = statusFlags & ~(1 << 2) | 1 << 2
print(statusFlags.bin)
As you’ll be able to see we have used various bitwise operations right here. For the primary examine we use left shift to create our masks, bitwise and to extract the worth utilizing the masks and eventually left shift once more to check it with the underlying worth. Contained in the second set operation we use left shift to create a masks then we use the not operator to invert the bits, since we’ll set the worth utilizing a bitwise or operate. I suppose you’ll be able to work out the final line primarily based on this information, but when not simply apply these operators, they’re very good to make use of as soon as all of the little the main points. ☺️
I believe I will minimize it right here, and I am going to make simply one other publish about overflows, carry bits and numerous transformations, possibly we’ll contain hex numbers as effectively, anyway do not need to promise something particular. Bitwise operations are usueful and enjoyable, simply apply & do not be afraid of a little bit of math. 👾