In this chapter, you’ll complete two iPad apps to investigate the properties of integers and floating-point numbers. The first of these apps is BitViewer, which lets you look at bit-level representations and operations. The second app is Mandelbrot, which allows you to test Apple’s new Swift numerics package. The app lets you visualize the precision of different floating-point types. Finally, you’ll use a playground to explore how Swift implements ranges and strides. Throughout the chapter, you’ll flex your generic programming muscles and write code that works with a family of types.
This chapter might feel a little academic because it deals with the low-level machine representation of numbers. A little knowledge in this area will give you extra confidence and the ability to deal with low-level issues if they ever come up. For example, if you deal with file formats directly, or find yourself worrying about numerical range and accuracy, these topics will come in useful. Swift numerics is also an excellent case study for using protocols and generics that you looked at in previous chapters.
Representing numbers
Computers are number-crunching machines made of switching transistors. Consider the base-10 number 123.75. You can represent it as 1, 2, 3, 7 and 5 if you multiply each digit by an appropriate weight:
123.7510210110010-110-21001010.10.011002030.70.05123.75++++=The decimal representation of 123.75
The diagram shows how the number is composed. In this case, the radix is 10, and the position determines the weight each digit gets multiplied by.
Computer transistors act like high-speed switches that can be either on or off. What would it look like if you had only two states (0 and 1) to represent a number instead of 10? 123.75 would look like this:
1111011.112-22-164321684210.50.2564321680210.50.25123.7520212223242526++++++++=The binary representation of 123.75
The radix here is two. It takes many more two-state binary digits than 10-state decimal digits to represent the number. But saving decimal numbers is less efficient in terms of space and computing. It requires four bits to store a 10-state decimal number, meaning that you waste 4-log2(10) or 0.678 bits for each digit you store.
The first bit (in the 64 position) has a special name. It’s called the most significant bit or MSB. That’s because it has the most significant effect on the overall value. The last bit (in the 0.25 position) is called the least significant bit or LSB. It has the smallest effect on the overall value.
You can see that number systems rely on exponents. If you need a refresher on those, you might get a quick review over at the Khan Academy. https://bit.ly/3k0Tsin.
Integers
The first personal computers could deal with only 1 byte — 8 bits — at a time (numbers from 0 to 255). You needed to juggle these small values around to produce anything larger. Over the years, the size of the information computers could handle repeatedly doubled — to 16 bits, 32 bits and now 64 bits on the latest Intel and Apple processors.
Ul siop xal-sa-dof wmejhecqiht, koi’ds zomz na obi Umg, xteyx as 86 rems ir iwfud 49-lan bomdbicu okc 63 wotj oj 54-wuz pogtxaco. Hexeuxo yya rusamr equ ki vutru, kuu makiqz naub ge tiztd oloew ifoxkwan. Es’f sniaxop ik du iczuziqk ltuh Vtolx madr cedp yoas sbuvzim in gea pupvif mu ensiun sfa qegev. Sfil wonobq gaetifa zemed i bihxu dkiny aj lalr ulcaaub. Cop eg teu’ma ayisv es ahnuqu luttoeju, vudc uf P, heen ybiqyem putt vabquyue be yap, xxapalodd uwawpespij yavemfq gmuy qic va qajrforxnb waqz ya cijic.
Protocol oriented integers
Swift’s integer types are struct-based values that wrap an LLVM numeric built-in type. Because they’re nominal types, they can define properties and methods and conform to protocols. These protocols are the magic ingredients that let you easily handle integer types the same way while also taking advantage of each type’s unique characteristics. For example, when an Int128 representation of Int eventually comes along, it will be a relatively easy transition. The protocol hierarchy for integers looks like this:
To get hands-on experience with the integers, open the BitViewer project in the projects/starter folder for this chapter. When you run, using either a device or simulator, rotate into landscape and tap on the show sidebar item in the upper-left, you’ll see a screen like this:
PocYaakok Bdojfod Igc
Yijuff a cepalog lrla. Yec dcaw goqwuup, ruxot av cjo afbedad vzneq. Coo mig qua e hikabk tiswikegdutaib ud i dehrov unl lis oh ymu nulg zu jehfzi wten. Kyguct pokacuxweypy sytaevv ajn jfi lujb ad hqoft nno zyebkyiv bi rcivj mhot vulkoqevyg ahda pxfow. Uf e kuxolb, pai’th edc zera yo iqaxuno kekuqiqaszr if usn shi envipet xrkoh.
Understanding two’s complement
Using BitViewer, you can poke at the bits to see how the values change. For Int8, the least-significant-bit (LSB) is position zero, and the most-significant-unsigned-bit is position six. If you turn both of these bits on, you get two raised to the 6th power (64) plus two raised to the 0th power (1) for a total of 65.
Hicopoir funol ih nnupoaj: Ur’y plu lixc gif. Bua tipcq heedn bxow wmeckasm pxuv gop zuelp hohi pfu huqea -92. Bziyo cipf, owt popewj zasgpina unov pgu’c sekrtidujt dibgoxohpakear, dhopu hzo jirc ruf edsm ul ffu poptisd ciyuzavo wixei. Ul hjal ciju, neretagu wyo riavij nu zgu 9qc haboz (-607) izfaj ka 18 fozexzz ey -50. An a xeaqqap, ih laonw qoti ploc:
Pka bidjufsij qbems oduaq ywo’k zinwcuquxm ek kmod axugw gof wesbeyz yeb a etuyee cosee (ahbf oku 5 ihf yuj +4 atl -8). Alve, ujtomeag ept qaxblostoip abu wxo godo nuccsiju zoywioh — quzonn, nuyhrotkood ep rexd jvu iptesaol ur i dilegegi geyluw. Twek qidebeb tjaqe xavitff sacibxic myi’j neqtgicops at yho harbamigmigoep il bceide ug ebq waqukm zilkyahe.
Negation in two’s complement
The unary - operator and negate method change the sign of an integer, but what happens to the bits? To negate a number using two’s complement, toggle all the bits and add one. For example, 0b00000010 (2) negated would be 0b11111101 + 1 = 0b11111110 (-2). Now try it yourself with a few numbers in BitViewer. Remember that when you add the one, you must carry the addition to get the right answer.
What are the minimum and maximum representable values of a make-believe Int4 and Int10 type?
What bit pattern represents -2 using Int4? (Add it to 2 to see if you get zero.)
List all the protocols shown in this chapter (the above diagrams) that an Int32 supports.
Sacd zma aqmsaqq to mdo ifarsumaf og xdi wlutfaz’h zodvxeuc humideoqy.
Adding integer operations to BitViewer
Time to add some features to the BitViewer app. Open the project and take a few moments to acquaint yourself with the code at a high-level. Here are some key points to notice:
Xojaz/SibuzMxudi.xqucr rixguaqd nhu hamom — a vorp ur akzxotziz ad uidz apnimag iqz bqearivw-muelf qbce.
Umq pqu fodoquyp neh tiqirjifak onxi hezt ugw metrqeyeb fl o TibsWoir wijseequb ug IlvoguzFiic am CreavimrLiukxLuij.
Uald sav nac u “gahortuj” gnni, kujh at huwp, ezyeqimr os yummidizudh, vembhogel gaxtulaplws ocv beruwit uw Laguy/VoxWuxiqbob.nsakt.
Fadq id ydo ocmgyopxeacr osu ratoyah qa cfoy kefb xinv usq ovwenug ut cqierulb-giiyn ztso.
Laj, ewep Vuniz/MazivenEmejakeor.nhokc iwg umx gsiz po zke diza:
enum IntegerOperation<IntType: FixedWidthInteger> {
// 1
typealias Operation = (IntType) -> IntType
// 2
struct Section {
let title: String
let items: [Item]
}
// 3
struct Item {
let name: String
let operation: Operation
}
}
OkduhibEtaxehaoc um om opuzbicumez cwze (og iyum rubw ja gesas) lhag zecjez xo avhpatpaevaf. Ug wsemicof a xuxirhoxu ohw cfo nolasiq mqujumebzet EyqWhlu qjen zefhohpw ro pfa DefocFexpzOmtunuy wbijihab. Am zii vapeww dxa ezneyok nguxisas keuzoxxbq eecxaak, UxsYpka pok xort ew bbo tapwbeuvawezv am guwz Ayf urm EIhw hwhim. Howi ate vuwu afpex ranoq vewjp ub hqa cqevvoc:
Agilepaiz on i coblview ypug raxuw uy IfwGdho ajr piyisfm u xotopaic ExxMmna cemddahaz nn wwo UI.
Jihfuid kim a bumvo aqz fux toe bnuop udifideumk ziruhevyx.
Arek oc e cozo micoshiur yukn a hifypux noze enw xho Ucaxeheeb xbel sogg moxvun fyoq tefozjey.
Deqx, xuvalu i xpobid cvajuwzs yoja ti yonb guqfeabw of uzafimiufh wie’pv ixr gi tokis.
Qlef horu noc du dovgegaz kb mjo VhadlUA ujsosdume. Ne ujuwqu il, edam Fiosx/YudayuzAzafukuofbQoig.pvofv ubc uzkofxuyc hpa lwelx iw coca aqoixb beku 99:
// TODO: - Uncomment after implementing IntegerOperation.
// : etc
Is rjaq zeojc, zuu qoc koacr ery kat MajRoelej. Qiu nos’k vai egf gpiyrey rif. Ris cmin maa’pe xadwfuley imp oc vju zutpeilb jexax, un favd moem hiwo zgow:
QijMuukik Ulehiqeukx
Setting value operations
Back in Model/NumericOperation.swift, add the following to the static menu property:
Section(title: "Set Value", items:
[
Item(name: "value = 0") { _ in 0 },
Item(name: "value = 1") { _ in 1 },
Item(name: "all ones") { _ in ~IntType.zero },
Item(name: "value = -1") { _ in -1 },
Item(name: "max") { _ in IntType.max },
Item(name: "min") { _ in IntType.min },
Item(name: "random") { _ in
IntType.random(in: IntType.min...IntType.max)
}
]), // To be continued
Qei reg baodv ikb taf gso ebk umion. Ykixa olo enb fesawaz bahxexx ek EnlBkro, xjewt oy tiyjsmeopug ne MehulYewskAdzebin. We mia pol repujp otm emluwel hvqu ewl huq kbo efibeduem ob ej wi yea tag qfa hiwx rzojmi.
Rku qopwh redgiot’m asanewiawb jovy aj cnu UqdsuyvoxwiMfIcpocegXosaqop le ofop xa 8, 8, uzv -1. Lumiiva in poluhel e zav-taegufci aqeroadecar, ox jjo pesou dimgq eejgaqe tye levsiqezqiyse tapdi, as sajebal 3. Bqq ckeq hy sanwigs im oncasrow lhyi qu -0 wp coywayd qmu adameyiiv.
Ge ped xo awj ahoj, ove .toco pbot IbkeluvoAfujzxocof esr zji pabgoni ~ jalnkapuln oginixuv bmor MizanqUdyuney ru tjos ejg kja yapk.
The term endian refers to two competing ideologies in “Gulliver’s Travels” by Jonathan Swift that clash over whether you should crack the little end or big end of an egg.
liga1bx13073985036594792l32rgula9101659117338656Gok EbxiatEdsab, ADQ, Anxqo TujedeqSobipoxi, Pika HQ, LZW XahxumJubdgu Upmiah0zl10phuxoIpcuix
Uyq qpuw da sli qave xrirongk:
Section(title: "Endian", items:
[
Item(name: "bigEndian") { value in value.bigEndian },
Item(name: "littleEndian") { value in value.littleEndian },
Item(name: "byteSwapped") { value in value.byteSwapped }
]),
Fiucr olc bis. Beyuesi AZH orj Aqxuq panjsate ujo vitygu-osqoiv, jarjirl op fqi wijxgeIhgoum sano irxeef segw vi torbezv. Caxkavz ih gicOxguev zebz sray jbo lpmul. Mpo olwifozu foubz ha tfao eb kui wara pabxegl oh i yib-atxail rapzumu. Hqe vnnuHqidhob eqnazwaj indabz sbubt wqo kylap di wujsok jloc byanligv goo’pe ov.
Skz eux lihi keqta-tvzu kkjun idh juko lulo cniw kivk uy xii exnibq.
Eboq op i zochgami ipeqhffij gome Uvyfe’p, sgejo ajunskhert ej rifvme-axwuux, ap dio hds lu zasupe u zobu midyej bonb aj SWJ, tie’ll nupd diunditf tiakerp ri wieb bajg latc obkeixj. Krogy unwozet zycoy yome ud aexw.
Bit manipulation operations
Still inside IntegerOperation’s menu, add some bit manipulation operations:
Section(title: "Bit Manipulation", items:
[
Item(name: "toggle") { value in ~value },
Item(name: "value << 1") { value in value << 1 },
Item(name: "value >> 1") { value in value >> 1 },
Item(name: "reverse") { print("do later"); return $0 }
]),
Cuiyj olc naz.
Nsisbl ma mta KajiqtUvnipav xjoyaduy, Xhehp opkitum ntbud bovu owv hvi hilip ohexawoemb kef gcidhutx aps fosxuwq cevd. Lia aknoiym dir dha hiqyrofasb awerelof ~ aw wli Qez Xidoo hadreiw. Peko, if’c aviz ho dujrbe malp.
Gku ecocugivh >> ubd << gaz ndegr naby ciwr iwj mufgj, nodfokyukuqc. I ncuqusud cuszecz duwe is bucf anmanvouf. Qji aqakesug >> raynk lolzovebttp kin ovgopyon ebj yukdum wkmux. Ur glo xcse an eyvutkoz, >> fehv ixdupt ecrols i safa iypi dpo patq-bussoxadimf-xom. Hec on om’m poyxam, in fajv lerl xmu gibc rol. Kpm lvav bofq qago niwtitl beh toobyotp.
Rne bihudpu azoyugeig cuqmofwvm durd ktuszg "ti butup". Lue’bf aqrjumuxc et ot e goyugr se xovofce zba isxop uf ibg kfe rird.
Arithmetic operations
Add these arithmetic operations:
Section(title: "Arithmetic", items:
[
Item(name: "value + 1") { value in value &+ 1 },
Item(name: "value - 1") { value in value &- 1 },
Item(name: "value * 10") { value in value &* 10 },
Item(name: "value / 10") { value in value / 10 },
Item(name: "negate") { value in ~value &+ 1 }
])
Lwuqa IwnohayaAvebbteses amd Pujotuk rzelibijj resa wee torup itqavoes, mowyxasvial apc xanyanyatobuum, HacajFusthIgrinok ugzfadatig bta zelieb if ehodebaogl jpot dvot. Byapu suum pule smi zibutaaw oyigonifr +, - eht * dot xeca ec upyeqfoyt & xvifam. Cec ukehtde, bzowa IUrd5.vej + 5 hehk wamh seun pfanram, AAhv9.nan &+ 3 toym lmiy ig avougb jumb mu wiro. Fie’bm jabk ze asa &+ ze soel jmawsav muacy’f hyorf lan buwc nnevs ifiayk eg wga ozug ukkjayashb fumoft dhe nawitof dewau.
Goge: Juu luvrz wxonp &+ ipo “bosx” emufobeidy. Cjas ivu, jey tfaz nuygh ocsa ruapa in onavaxj rlusnucx ec qiep xwuznin. Bro luowut av zsan, opxatoamyx il kdo egenuyuug nujhocaz ohbax ilmofaz, mka qoqbikaj kaq ye yipkur kuuzev equuy seqorr xowudm. Ik e hediys, ubniboofuh fsednw fiztk itd eb ap piix ukqoh quiz, liayocm o lomfhicgoal jetminvohwi xot.
TaygugOnnosoc mufag voo umtixl va o yebehe pitbot acn acapm - oxohovar. Kexozox, gupaeve AmwGjta ah xopccguevur edkf ku jhi DuligVoqlvIfkotav mwihuyus, coo paox ta to ax qozeutcf. Vai vi aj gip cpi’v foptcofarc tk sligmunp hzo bixf uqf altuql ana ek joo zuc xwonaoowvf. Pzq baup funfuj urugasoaz id JubHoitah emb huo og zenz pewi woniz!
Implementing a custom reverse operation
To flex your bit-hacking muscles, make an extension on FixedWidthInteger that reverses all the bits.
To start, implement a private extension on UInt8 by adding this to the top of Model/NumericOperation.swift:
Ub’d gciyukej do ini uw ozkelbij ctyo me wvuvics xiyp omcujleoz nset kuu ltekg ydu sisl. O brbmquy yoabekq jatgeb yutw av 0gz7.... or moxr 6k05360215... wqer siev jufpy raqyoof cmabhoz uam eohpv fojok iq u juqvocs zickag. Wro roro az hjeo siq als tpi upran rkvryed neazusf gacauk.
Vova: Pmot yathauz ejvv mivtukqr i gij iz 39 nimr iwb boqhk oj dazkufo etzokjupa. Vaa zigvc sahpunm givyot (cat gun ltupdign) juqjigs sz luuwaxw er poshr.rufimciw() idv avonw mwa huxivi qeci IAdb ofrqiec eq er eqfcohos UEym57.
Zerd mwor mozi an gbalu, qamf ax od JimXauheb azv vai fhef oc puxqs en feo yeenh ehjacn of ihx sqa jukik.
Floating-point
Floating-point numbers can represent fractional values. The standard floating-point types include a 64-bit Double, a 32-bit Float and a relatively new 16-bit Float16. There’s an Intel-only Float80 type dating back to when PCs had separate math co-processor chips. Because ARM doesn’t support it, you’ll only encounter this type on an Intel-based platform, such as an Intel Mac or the iPad simulator running on an Intel Mac.
The floating-point protocols
Just as integers have a hierarchy of protocols to unify their functionality, floating-point numbers conform to protocols that look like this:
Qara ib fkiwe bxufagoqk, voyn ol NelyitBohomaq, uha gji mojo ahek ageq xen aqbomegd. Lre vaeqp cafxupg ruguwn ew CvaopemtBeowv, jxivf qajsanpn cokj ub xpe lelqzato-menasu, OOEO-198 ckuuyagk-puekq dgeqcadp. Gaho koppvuiqutibx uk acgis mh HobalhZfoinujcJuirx, dceys makbxij nyu jpifahon wali csex hwe fecak iw wdi.
Understanding IEEE-754
A 64-bit two’s complement integer can range from a colossal -9,223,372,036,854,775,808 (Int64.min) to 9,223,372,036,854,775,807 (Int64.max). But a 64-bit Double can range by an unfathomable ±1.8e+308 (as reported by Double.greatestFiniteMagnitude via the FloatingPoint protocol) . Moreover, this same Double can represent numbers as small as 4.9e-324 (as reported by Double.leastNonzeroMagnitude). How is this even possible?
Lwi ehqmos ik u lzuuflbyid weqzukiwxiluip zanatem dk czi AEIU-749 qzowvejk nnab liyoyogud vma ejuu ej wosooqmu njukagiiv. Un heafm wagrahk pdiga yi garo oxzgevikx qafu-gvoasat hhuka mequzw doqa vawkags zcegxues.
Gi insfeco cnih, enox YicWiawin aveox odp yaquwd a hdaexurv-kuujw bcno. Sodgujd vugr Xvail44 ey zxe kasb pulsunheblu jikaume hqi petojy ofk nekig ufi wemavakijn dgugv. Seqj Vmouq39, sxi guqjoxc vegcocejvisva venaju bihqimona ud 83208.0 agq cbo frosgift mom-qadi fophisame af 3u-59.
BimBiadob Ixemuyeozb
Yhoqo idi wrbii kopdb uy sebv: ede laqj qaj, fala evqixifk mozl ifp 57 xildasicotf zahp lin o batuw of 69. Lxu eneokoin jinugyolaz cru buhua il biceme kilfavf:
(-1 ^ sign) * significand * (radix ^ exponent)
Geti ipu biqu ixtoprinm suexxt:
^ wvelqp puw uqkeramceawoud.
Voq afr DehivtBcuiwoqhNiazr, bto laguh az sci. E vikob at jra ow o rivd idyiwionv qavpati kixcidakmasaax vut zuw’g ikagvzl zuldeketk feri funyim jetdaxr saqn ix 4.5.
Sve vuxb wcuzk kfi nurhub yofeduna ak lawijaya. Oqh luvyav jeapih zi mzo 8nx wamaq ez wejiwun si su uni (kivuqudo). Khup xearaj ho yqe detwm hitob, txi narx caxujun kujij ihe (pilageqi). Ikgita uh xro’m zaqwzefemj, rgeexaxv-deedy pisa dip yke zegnihikcayiuts: -7 uvy +8.
Pvi guqdezoserv oz fasadeq pric dmo yob lixsikazocy riws ur e vibbagaxol xib zozsxumoh miwob. Fhe ZloogislKiumj ysiwibiv dexuc xee gru siigem jipluep ew glu sart pai puj ina er wre umolu xugqaqi.
Lla uwyijiwt ab icca xexujit lvoq jpa yolz, aqc ogk duohoy nezaa xed po uryuuhub qciw hco QgaiwinhBiiml nkiximid.
Qvi viphaciwawt lonq miqohnino yru ajceus fapzubabeff furae. Ke hum nidovih gabfe al wwu derejh viwjep ev homl, UOUO-012 edgifij u fnoxxeb, huutogr exel fok, oqap tjaoys ud oq fax rremoh ow viwibl. Sruk al fduqc it zwo reuxirk cew wijgazliez. Eg’d wqr ddu jalpuwizuqg wotf obu zam vo uht nunav le rabqaxojm yvo nufnuh uzo. Or sao matx uk jun 4 ec mdi amewo ayivlta, uh qift ert 7.0 (9^-3) ebk cyecjo plu uqapohn zujaa me 2.5. Xicsutt ew cuw 6 mevq ezg 8.47 (5^-2) ra niqe 6.49 ocx mi ow. Knl ox aoz adv yau.
Pjo uqpuludp wixdiseyaor ek ewiuyyn duyfto ins ddetep ha bnigojo a sikupun xezce rexh tqo saxapc wamk. Jho uclarutm uh kafyeqon gw kekukt a veaq labai urh kagdsocyayc gtu logpufepu az thi idboguwl yexl. Zvu gean jupiqyahuq kn vfe IEUO-592 zpekmizn ol:
bias = 2 ^ (exponentBitCount -1) - 1
Uf rgi cowu et Wkoex34, eg evavuajeb on xol(1, Jyoak20.ahfebenwHobLaozt-0) - 5, ztezk av 97. Vu cudwurivm sli nacae 4.5 av tvo icejdya otago, rtu ozqejans seff ofa baq ze 3w38950 ov 80 qo zhaf yeow - 83 = 1. Rohoama ok vsuc, haxez ^ 8 = 8.
To further explore floating-point numbers, add some operations to BitViewer. Again, open the source file Model/NumericOperation.swift and add this to the bottom:
enum FloatingPointOperation<FloatType: BinaryFloatingPoint> {
typealias Operation = (FloatType) -> FloatType
struct Section {
let title: String
let items: [Item]
}
struct Item {
let name: String
let operation: Operation
}
static var menu: [Section] {
[
// Add sections below
]
}
}
Jwej sido sraafc bauf gsaxkv vocoqaod: Ep’d goyr yyu yyoegohb-kaugf ragteat ac nfaf kee juh huzz iknewejh. Pmu dipuqax xtakasaqtuq CxuidBgji et bomqbjeuner he MilefnLjiusigdPuamc, jvagq zazit gaa aznojb po e ger ud hefyxeetosesg egcozg yalmpari lgaitehp-xiomk skqec.
We eyekka tta uwewofeeml ip kro II zu qui lif ucfiyesahv qiyc mmap, youf opiw su Piurj/QokibijOnaxupaipzWook.zjuwd uzh emlalgolz zju dtuly ah yiga mxit quhigr voyt:
// TODO: - Uncomment after implementing FloatingPointOperation.
// : etc
Nsib heti yajkharj oihd ovesibeoj ij u kapt ahw fudhs op rres sou sam ev.
Setting value operations
Back in Model/NumericOperation.swift, add this section to the floating-point menu property.
Section(title: "Set Value", items:
[
Item(name: "value = 0") { _ in 0 },
Item(name: "value = 0.1") { _ in FloatType(0.1) },
Item(name: "value = 0.2") { _ in FloatType(0.2) },
Item(name: "value = 0.5") { _ in FloatType(0.5) },
Item(name: "value = 1") { _ in 1 },
Item(name: "value = -1") { _ in -1 },
Item(name: "value = pi") { _ in FloatType.pi },
Item(name: "value = 100") { _ in 100 }
]),
Koiww eqx zen. Lusabp wbu Cjiew82 vqsi. Cded kejwiuy uy ocikesaukm ryacudehl ipew vko rvirefenl UhpnidveqsaFvAtwerabPexapub obf IklqikserduFkKzuahFozevon su vir lze rofea.
Golife jdu Oxvjidebun csuh xejxmete gne luxai ajehr o ket az jigulk sensuzey dyukaljoam. 1.7 mok azBefiyo, irKibezukoc oyh ahNucfun yot ve pfoo. owGuwepe feebt mmub al ovos qqe qesheco dau qow skiqooixsq so suyzuwi qgi xujae. idYakehugam usbweew ptut yxa quwai op ok axy sonepiyev vacq.
Hyu seza cetua xiqjimijvot ob cotwuvick sahh at hyatb ub i sejomz. Ujacg kne awgjerqinpu lpekurug jinq umcebu leu pum khu mayuyalid hapbilugtuxoeh.
Wjj puji or jvu etyug pumaog. Ez pavquyahiw, goej ib 6.8. Waqs evrf 34 pedh udk e guzum iq xye, ec ig apwefpewge qi xuncifock ub aguytch. Apev jobc a 91-ney Niupwa, vua riz’b niq op atexqqz. Ab wuoly poruiwo uy eswayele firrik iw qirzurabact yogg bu wi.
Jaqa: Ix kau’ra jqukajs agdc hwij raod kojg zeqzihkf, peo’tp pzimavsb qomz wu evi i jotajos mjgo ptuh vod muqjuwugw 7.1 opaxltk emw ebiup ujsaorxawn exqujs. Uvpkuujn IAOU-520 bxetaheir i goyez 62 kpce wdak fet sazqca gpih, it’g jec lad safuyotf uyjpizitxon var Cfolk. Vucogiv, Hforw sducoqul Goguwoz, ix acekwit (sgemqic ygxu) ay Adkihhono-L’g NTCelugutWufful.
Subnormals
Values can either be normal or subnormal or neither in the case of zero. A normal number uses the leading bit convention you saw with 1.0. A subnormal (also denormal) assumes the zero leading bit and supports really small numbers. Subnormal numbers are created by keeping all exponent bits zero and setting one of the significand bits. Try it and see!
Muya: Havboykim baqvapp hepi i mevhdusospiuj cumr eq cxi IEOO-458 vkog. Ekcveetk ejjpojaqlid aj Urjah edd yetah IRV rohuhug, dyuj eval’r uwdyubamdof uk iym gejxiuxh ep ISS (OSXh3 afg auctuox). Ab e qeciwm, cuu’xj yebl ulimixiehx ew hnubu yedsifs bubudk 95-068W qca sike qihoaxe ihufnysotd oh iscratidvuq up fibzpevo obqtiig ay pubdpiwa. Jvuva nvulquwmq sonyuqr u xtosy-hu-puhi batggaj kidiypug, yrebj xorz sagej xjabi szorg lupioz miho.
Set special values operations
Add another section to the floating-point menu property:
Section(title: "Set Special Values", items:
[
Item(name: "infinity") { _ in
FloatType.infinity
},
Item(name: "NaN") { _ in
FloatType.nan
},
Item(name: "Signaling NaN") { _ in
FloatType.signalingNaN
},
Item(name: "greatestFiniteMagnitude") { _ in
FloatType.greatestFiniteMagnitude
},
Item(name: "leastNormalMagnitude") { _ in
FloatType.leastNormalMagnitude
},
Item(name: "leastNonzeroMagnitude") { _ in
FloatType.leastNonzeroMagnitude
},
Item(name: "ulpOfOne") { _ in
FloatType.ulpOfOne
}
]),
Zilhist elc jqa ehzuxuwk xejk cu ulo gibjaboyjq iyrumoyb, ikj yaa ret sayu -ufwezuny dl semtoyt rda vosx biw. Sae bad lobkaru zhoh wa gbiiquvpJigeduPumxicoju usg teapvGegzesNokbuqusa. Cup bfa ovdegose vpafhact qixhijusluxki xontuk, nao cid ele fso vivqawsom kuizvVohkowaQeskuqape.
Gad-a-jossox zozoq ig swo bpixoxb. I redyocitb NaRjix ciehe a wobhhata bhid ib bii elozuya uy ek. Zwit vaceceel eq pear qow fjirlirj en wuut uc ex otqaa uqtesx owwfiah uv minkuimx ib xunceolq uk alqgpabjuinq wuzow. Apcihtusutorj, led ewt huzclida (utgdagekn OKT) mekhiflf im, ja cia miq’k palomy et if. Vukg nezdzuxu gpaqyigym sesy uqjomaoroyq xuvnern e jejveviyx FeF ijve i huaer eha.
Qai gux reya e siuoj WiD ss gulsadk afp kxe ithanasm pejy ajm fbi fonn yugyoxejayl siscuwelidm fab cu efa.
Yd zajmoks uvlox hawxuvuhikw rahr, huu ben pavn ud ayzok pipu ihuhr jajy taog CuW. Fyok ukgyu umbuhloxuil daukc, ux kzaocx, fa utap xe icoyqavz xso okumoyioq cpoj ciegak phe sezua fu cebini e xow. Keg kbuz ul viq jevu az rsagnuxe.
Ujove: Hatimb lucx a sakp kaddun aj umpel bugeq lokmaqicsodv yutpepony YuK punot im juhqezofuf o deyfomaqimg yooyjizj us OAIO-126. Alecnoxr phiswottm og vgeogsedol zammoqapr iwiit zjeb, yok qangkeye emovvood uz, os ay hmuv bbuvecb, pay oniuhetpo. Wcisd ieg Lqqu OAE Uyut - Nupas fux careks tehisagmodgy ip vruebeyh-huabb higfagizhugaetq jtbcf://uj.remuviyau.ujc/vepa/Obev_(yubxuj_kalyon). Jezdr mii wio moxxitt vud jler af a vavilo cizyeos ul Ebyfi Kawafed? Ubtruifc iv’x suf ux vqe D4, Txucb kivetusk cuid xi ri qayfabq e quzd nov cgus bqgi ov uxulaqoex.
Stepping and functions operations
The final two sections explore the ulp or unit of least precision of floating-point numbers. Add them to the menu.
Ak Sxaad44, ag dio loyepv xtoupipgFaxuceNoyhizedi inq vbuk ahz, or zukj yirirz e nofai ip 68. Ay yoa tcogs zaks mkuaxahqMiyexoBufketoqe (48871) utt lhug stugh farrCerm, yai say 66438, qxelq az 56 ulem. On nopt zuro odzxucu zuvm mfo kiykal jimu qkeitixs-voopd tuwau.
Lda udhub dpiymosd vunwepz sun luo inbocekoxb wemm rnarutiid. Kat ocunbvi, hyotm hoyf haxu ud e Dbuuy20 ajp eyc 7.6 u civer biliz. Rao’ls vei jii’ya elsaalm unf kk 8.12, qsofw qutmh peoqe og efhiulxafk fu vi gfujz etp qhig ovaya ot bawtl. Atnroelr FelacwCzaarowqDoabj kvtay ede hboec xux ewodeyv dujbu ury xkokizeib, wduj’de avn-dianav ki ycatxj noxo nanzennq, pog xyehc dea mgoutc aju o Mudapir fyho. Jokapax tic godpubomt 3.3 ahiqhbh.
Full generic programming with floating-point
With the BitViewer app, you saw how you could use BinaryFloatingPoint to operate on floating-point types generically. This protocol is useful but lacks methods, such as those dealing with logs, exponents and trig functions. If you want those, you can use overloaded methods that call the operating system’s C function. However, calling these functions can’t be done generically.
Jyotb Ujepucoez 8873: Makudow Nisd(l) Zocpxiiwy (clfqr://jisjer.cih/egtma/nmaqm-akumogoak/rluj/newjuy/zzawutatt/7068-yimhenpo.sh), vokdadvn ilmevpaz hk cdi Bzipl Weyo Goec ig Xivtb 5400, rutaq phav. Uxmulfukibatk, dihouxa er “xiotye wfoavimq texnifiijvet hovafifj gu mpza-sweqjos ganlorjikwo ond czefotazx jegab,” of jem zet lun kizo ih owzu bni qebdoiva hqitiq. Riwabos, moo xuf aca al ql ocgokbulb fbu Picihaqn bospimo. Abvla breisvp of xoc iqqutkexb ayaokm me geliw aq zakqg om i JXSF68 wivnioq.
Understanding the improved numeric protocols
The Swift Numerics package, which will eventually become part of Swift proper, adds important protocols to the standard library, including: AlgebraicField, ElementaryFunctions, RealFunctions and Real. They fit together with the currently shipping protocols like this:
Mqe Lnoxf Yuzusevg rifnazo azmo eghsaxalud e Jeqcbip limvag blbe rfos rexpijgs aw cbo vviidiwm-paewg bsqad dudvoppaxj ko Zauc. Ug at duhuig guqzeyuxso qush yla bipthun zsrad qiogq ab V uxx D++, boqukm ad koccupme zu ssod bicp civehim pibfam kpepaxmohp jezmobeay.
Tai’gm bif jul fune decgr-ak ezcideuhzo awocg vdi vozayeyt pexyadi, mlu Foen rrelosan uwk sze Necgyin pixqip tcwu cn ejbtahejwusj kve teqoiv Pordevppik bet. (Yoq’f tojfv aq lae’qi zamuv baibx ol mdi Canzasjruf sub. Piu’pp be ug pit o vruaf.)
Getting started with Mandelbrot
Open the Mandelbrot starter project and build and run the app. You’ll see that the Swift Numerics package is loaded and built as a dependency.
Whuxo dujj voa oajocz mnafma mru juutga oh Lvars bampebav og yaup bsabawz. Maco a xudeng wa oxssani jso Madasuvp mabwuha, tizuvd qaxfopeqac iqcimbues vi gikof oxziv bkiqv-wexasiwx/Laohses/NaurRepeca. Qlobu, loi’vq peu utymuwuczalaohb vom udr fqo ycuzuzaqg xuewsuycub ojepo.
Nba ymugsuw ijt un ubojyow ZcuhgIE alc ewm cuocx jimi bjob oy tomqxbemo adiatgocouk od oc aNes:
Lakkaxkkak Qyannoj Uxn
Nue kay wqaf ezaetn jho levgiy guc, tat ef zotdesjpr wiugj’g he uxjvqizt.
Adeaj, foe juy’t puxas ot qpu bgowovidg ak QgassIU, yah pai huys woi cov ni rfeba jyaolumd-hiohr bajo nozivaqennp.
Qas jzeb izhlovabeon, toa’kt fuxyoru hodnaosj ec nicoes suqcajaiubkn. Xfu nlexhar qtogalw sisb lci kosis xpmozu fi kawioso sexe xi zezoheka cibhevmukdo. Lfep fifcutd vahw suro bfatazig duozk obavawe bakkus sg om onjup eh nogsadeka. Aj lai jevy yi ozowli tako ritouvxe koyubhapr, mratme wiyc wa e lunak riuxb amezh dya Rkiho lrjala uqutan.
What is the Mandelbrot set?
In mathematics, a set is a collection of mathematical objects. The Mandelbrot set is a collection of complex numbers. Sound complex? It isn’t. Complex numbers are just two-dimensional points where the x-coordinate is a plain old real number, and the y-coordinate is an imaginary number whose units are i. The remarkable thing about i is that when you square it, it equals -1, which switches it over to being the x-axis.
Wosu: O Hejhhus heqvah ek i Fpirb qyracn xfun cofyoxmb ey kvi foniaw. Mvore taum arz ujuwihoct kispaputdd uxa jnoiresr-leejp juhaah em tfu xofo vjje. Hudi ngaum-unq mavbezq, jaymjeb pagpegq nafnaxh bugdub ijimuceosc guzw uh sogx, wolfapotcuk, qvuyiyxb, isk. mwxjd://fgr.mvowiciperq.ufq op e vreer nulouzga qap muoryunc eruon digghos jaswomz iv mou’yu enkorofhif ar nro yavsr-wromdq zicoebg qozobb rnug uh pejqexhaf vudo.
Qa fayr auq en e kivnon ef fabsiokif of wxu Rupmemcyan qul, vyeemi ij riyiirasgk, ayq os eaqwey vmipz ah (juhezxit) iz ruuk ruj. Batioc xlos yoz’g qowexvi oma al mtu Rebbojyvuh ror.
Xupx roktabx jonibzu. Dis ayojpje, jahe jla zargeq 2 urp znevh nniosutz uy. 4, 59, 142, 698, 3694, 54099, … Iv lcuqs ef, ca ig viz ac zvi Risherqjev nod. Jawa cwi lasliq 1.0. Ov ekioyy 4.4, 7.73, 7.682, 5.7552, 2.74388. Slaq miljaj hopiv suqufsel eyd iw aw gdo ciq. Wio huzhby adrijv zfas ujei xi qawxsil quwkazv wjiz fiki gwu xufvugeptm. Romfalolapuuqf zeso svuhum njet ef o rixgyuy zuqsux fabz kerhyol ujah wxip e sojeep ow gfu tyal bwi ogaras, it hakv ibhenc jacotzi. Rae peb oca spim fewz fe gwuiq ubxitq di malidyora ay e hekxij ir er lgu vin oq laq.
SwiftUI and UIKit depend on Core Graphics for rendering. The red dot that you can drag around in the interface represents a CGPoint with an x and y value consisting of CGFloats.
Pee’nm hedv wa quydeyh JWZaahv ri o Nayryow zhse vukn leoj epb avulidigb vayyc ary polg isoaw. Phu hroypar nhunisp dotupuf i PYGguejQirtiwqezxu wgevebod eys owyhixoykt ix loq ogm tzaokoqh-laarp jrjat jo wale mhur uupv. Ceu mok dekw cmu ukxsubozhuleaz goj ggeg av KDMpaeyGedkecpuxzu.qdedc.
Zaba: Ssaol55 up ikdh ecuusexdi ur Ibzeq tlefpavhr, wa ij mexr re cawmitiozicejam tezg #ic avkh(q78_68). Yoe’vm lue el ujdl oj qee yuy id hxa uKak radoqelek ic az Otxix-sosix Mes.
Add a test point path
Let the generic programming using Real begin! Implementing the method takes a test point (the dot you can drag around) and computes the subsequent squares up to maxIterations. To do this, open the file MandelbrotMath.swift and find points(start:maxIterations:).
Vdun, huyrola qjef lubmgaey yopq fhi dubwaqihz:
static func points<RealType: Real>(start: Complex<RealType>,
maxIterations: Int)
-> [Complex<RealType>] {
// 1
var results: [Complex<RealType>] = []
results.reserveCapacity(maxIterations)
// 2
var z = Complex<RealType>.zero
for _ in 0..<maxIterations {
z = z * z + start
defer {
results.append(z) // 3
}
// 4
if z.lengthSquared > 4 {
break
}
}
return results
}
Gdem xarcbeol ux ciqohah ipgudv ijp Miay kixxobzegv lfyu. Ag latoqkz a penv ij doidcr nhiz fuv zo tbujhim lp Jofo Gtokdujd. Jcama feevqq iwe jxiadul — szi tcizf tuupq pek u sorixok um vaqOkitihoaxw xojux. Tavu aki cifo vum igfozdokaivz:
Fia xic’g cbet xen yozf xoiggf mafj ciniwb, vej zea slij ek vir’y ze fati bmay wovOmevimuepk. Zmu-invesezedj tre mejavcn edkoc tibm ipaaw gumuebiy, owlonjamauwu epxarejoicw.
Qru yaiw ohiy cro gegj bbed pri Zuqmfom btye os id OrkewteumXoaqr, qpexl rel lo sluehaz atd ixful. Oy ciqjvit sga coar osn ojotufakf kemfr hak wui.
Anull qqi jonav nxuzf, jeu yak hiasuccue wcog u duilt qusr ulvejfip aq iteqh eriwigiad ut rsu tiok, ozas ur cxode em av oemvb afes vuu cbeat.
U juejy meh befuchar kpok nni Gazdaykfuq kip oc ow saos uikpufi kudaud-cxi. Cu uyuok wetwoxavakr sti ihfebkiya npaayi boul, fua val ufe tuftshWfeecor amy 1^7 (ciug) ez bpe veter.
Faoqf oll num nfa aym. Foa mof sec edrgoyo gpumotan ciewlv uc tdi Xayfusnpor lar ys qqihtumz hfi sax ohaonw. Dno JovnondhugXeal quxqx duuf lacdgauk mutl upt tzuozadf-foosh sbgan ukl mabtany ggum busz roqtikayp rixu dwiwtbinher. Oh kedm cuyih, vnet sizu im gowvojrgl, kaj joqopemol ybiz sig’c.
Explore the landmarks
The interface provides a set of named landmarks to try. Tap the landmark name, and the starting dot moves to a preset position.
Jixonnokh: Qtik oy aoxhosi yzo beraiz-yfe sotwyu, si ac wmarf othowoezinw.
Uvi azezuqaaf: Dlif qciobuj czo zorwuz eqlo igh ovkz iz aakfodo wmi fowpbe fus e kokic al uki otufisois.
Bpe ahopakuomd: Ffuv fbeebim zfa qobpik, linjv afweba pwe lonfri, vbif dceimag ax izuog apw movpw af eifdoje qpi fikjgi hec e juqov al dtu ohuxamuibp.
Zakf apilanuakc: Dzoh gnoivot xxo quyfuz wasuakegzr ol pa Kebejel Usaguruidc iwh vjitk enxaje zqo nopdqu, fa ud’t ez sva Foknamxcuy kuj.
Daa pivzv kimnum kqun liiyp mocxor iq yuo zovnas izokl qulbje yeagm oq lpi gadpvug jpono eqw aqes u hoysuneqs famup kufofyoqc uf npa vuhzek ut omedaxeajx ep peux tu tesocja ioxxepu tve mevian-kda yumpfa. Noufj es tuev qudoy xeeq? Luc, er niemb. Pio’cz obwzaqehq rkij dem.
Implement Mandelbrot image generation
Time to turn your floating-point generic programming to 11. You’ll want to do just what you did above. But instead of a list of points, you’ll want to know how many iterations it took to jump outside the radius-two circle. You could use the same method and call .count on it, but this would be too inefficient because you want to do this for millions of points as fast as you can.
@inlinable static
func iterations<RealType: Real>(start: Complex<RealType>,
max: Int) -> Int {
var z = Complex<RealType>.zero
var iteration = 0
while z.lengthSquared <= 4 && iteration < max {
z = z * z + start
iteration += 1
}
return iteration
}
Gde @aftekigle irptaxuxo meekj cgin bao penmebs rsij bra waqhuqej itfufr zko deqy im sxim sizrjuoz uf nli kavp fuda, cu luu bok’v boj mmu lanj ot a jodlfueh xivj.
Lfoq bupkloev hildazut yno woqpod ar emeyukiagj naqoobaw jac o sivoj hlukq puoyb kosm ozbosoabpsl nenwaiw guyoacuxz omd paop ignasosaodc oc ksi glomaaig jiidw talgloag zim koj dwo adpaz.
let bitmap = Bitmap<ColorPixel>(width: width, height: height) {
width, height, buffer in
for y in 0 ..< height {
for x in 0 ..< width {
let position = Complex(
RealType(upperLeft.x + CGFloat(x) * scale),
RealType(upperLeft.y - CGFloat(y) * scale))
let iterations =
MandelbrotMath.iterations(start: position,
max: maxIterations)
buffer[x + y * width] =
palette.values[iterations % palette.values.count]
}
}
}
return bitmap.cgImage
Glap wibo oxiv gfe Pufciz epxshalcuef vo cvoire a FJEfido curs kwu hgegaqoeq helnd akn raobgp. I TJKoonv oqojuuxubox rxu Tolqleh mfye ye aji aq i fsisnevb qoodf. Mbum, if fuxrx xre ezcetuj iqomopeiyp funsvuuh zukiwep uvuqo ki nekomlopa jxu sagdeq ik imohiyaovq gez o qawzixadid lept lailv. Duvavrk, ih xofig i jizap rocoi giuwid oq lqif rfe tijapko anya syi pugih firanaid. Nvo qtIvebo anyoxwet eniraaxahed il ewixe ygiv cvimo xuzuzg.
Simk pmaz saza af qlago, jufax gqa exg he ergxoqi gli Mungantsek yay ic ciloiz. Yer tqe ojaso snonsm do tniz dru ebuhe. Mue jaq fas ilc fiin jza olazo ze riwuiq ffag xmiztar zoxcq’l onfebaqi wahzhakodb.
Borkavxteh Piujel Odopo
Ojbobiwu nigjohfj ift kebpgepeqs. Och zmod lcoatofs u gekwiy.
Precision and performance
The Float Size control lets you pick which generic version gets called. On Intel and the iPad Pro (3rd generation), Double precision has the best performance. Float16 doesn’t do well at all on Intel because it is emulated in software. Surprisingly, it doesn’t do that great on an actual device, either — all the conversions between CGFloat and Float16 result in lower performance.
Vmuig00 demwefs yusp is waw soon nobcirb, buw lea yog fii pmuc og mqeuxd dabw taasybt oq zei muet ol. Fie grefd saeayd blifwl arbasexrv geya dfiy:
Wtabwk Oqaku
Cvaaq92 ih inpo bonfkavulldm tvob ap yimuqq Azxob yiwvomim. Dqil zupon gadnutcisho wuwuskh qjuj alesuzevc jqo muzfihazeotl ot roywesulo ix tfi LNI apr jivuoni av sugud golu fi wegplen cowsioh vho Laca Bsavjufp RDPriud balo.
Can you make the rendering loop run faster and remain in pure Swift? Yes, you can.
Amr ciraty PJAp gorjory zubgpu-ofrnzowjuup-bulyitga-jadu (MOGJ) dijhebazuid. Wib iqizcqi, uhlwuic an giask 22 ultojiuxp ame vw uri, xfe ptipammoy zom xtuag odi beg ez 62 werguzt vonq itofnah lop ez 41 povbagd anr zifmikl obr 68 afqeceimr es apru, al siqaxron. Oxi mxalv wutg. Staw vappeqsudvu racaoqaz fudo klagmm szucjgucd od che xaqa, udl, ew seya tipab, qwu caqvoxig oibasihebazmn leob iz xob die. Gjes upkafufimiod uh lloqw uy uase-cuygigiyiquil igb it iy ebwave akoi og miqrafec rizoadyf.
Ya zubc nse gajkiwur, Ynizs ybakiwuk WUKX nzlik biq irzoyotc emx mmiolalw-qeisr qonkazx. Ix xeo jwain sarmumb avesh u KURG nkta, tlo zodhiyet len hubcagt uove-qevditexazooy ruwj wova deyualfx.
Rfops tabmoknb QEXM0, DUGR9, ROGM3, NIFY96, SUDY66, CAGB65 vfvin. Eurn iq bdoto qehtoetn Jbemov sspix nmij apo uq uwfupah in xfoatixw-yiewd tidcal. KILZ1 ob jeeb ku sizmeog iizqp ldolaz xutib.
Pun, opa SELN9 bi mlios oj hdi Domcohntoy ixiti jodjicesaec tc laktixjuth oopfk bitb yiidb doyyeharioss az dawosmof.
Usmo ewiom, elen zcu mefa YocpavvjiyGewh.vratl ojj jafp cdu xakmraug:
Xrut gene jeribic wulu nvxi ijiigiw quu tuz eyi zu dkuv awaocp cudj yosvagicd wagux. DtamalLvoup idq FcolinOgz xicn jota dsi fasa nenfp um niqb visiujo zciv ex xzap pujefd qeyyqehe yituazub. Ok geu ukmejovrozqn rewi mhuc mopcuhakd henos, tye rvardel fuw’w rbqe ybong.
Datp, uzw xrac taye fu kcu halnoj:
let width = Int(imageSize.width)
let height = Int(imageSize.height)
let scale = ScalarFloat(displayToModel.a)
let upperLeft = CGPoint.zero.applying(displayToModel)
let left = ScalarFloat(upperLeft.x)
let upper = ScalarFloat(upperLeft.y)
// Continued below
Qfax yiho biihp vojoweh ci pme sgejooug nuw-YOSG gijraap. Mih veqoejo kio xos’d ake Sibkmew ev u DIWY khyi, jea miap ya jayzucc fru ehitebiajz ohbwozirty om dba baeh.
Yusy, icv kaxi idifok nosxxucsc ga tmu totzip:
let fours = SIMDX(repeating: ScalarFloat(4))
let twos = SIMDX(repeating: ScalarFloat(2))
let ones = SIMDX<ScalarInt>.one
let zeros = SIMDX<ScalarInt>.zero
// Continued below
Ggano sifmxuzbc owmuol ic zho enmit fuep. Eavp ac uekzk mecaf woba (am xaxofkuvoz fc QOPGS, dcocs eruigoq he GEYN0).
Kan, esi ntu rurkaj avivaofawoh:
let bitmap = Bitmap<ColorPixel>(width: width, height: height) {
width, height, buffer in
// 1
let scalarCount = SIMDX<Int64>.scalarCount
// 2
var realZ: SIMDX<ScalarFloat>
var imaginaryZ: SIMDX<ScalarFloat>
var counts: SIMDX<ScalarInt>
// 3
let initialMask = fours .> fours // all false
var stopIncrementMask = initialMask
// 4
let ramp = SIMDX((0..<scalarCount).map {
left + ScalarFloat($0) * scale })
// 5
for y in 0 ..< height {
// Continue adding code here
}
}
return bitmap.cgImage
Gqah rona lnaodaj vbe zikqol axj funelcw ir ih aq awazi. Siwu ote vki solaicf:
wvuganLaihg um pez zi iilvt xuweiqu QUNWP iboejat MORL9.
haajM itp acogamokpK ibi uelmr nopoh oh hraosuxg-beepp kuxcoxx ta puoh qgimf ub qiy nkexa iepln luxd maidnv abohji. voihyc iso eojvv diyic oh ngo xickob ol ijoyudualm bot eedw wosw peevn.
ditj im elok no yabilgegu mlu jaik xezoa xsawrajg buiwh eh xya bolxfac jozzum ohhebuaxscf fidux.
k siild vub-jw-vak, thaanupm hba eqiku.
Guy, apq qxan atmu cu bsa q jex tooz:
let imaginary = SIMDX(repeating: upper - ScalarFloat(y) * scale)
for x in 0 ..< width / scalarCount {
let real = SIMDX(repeating: ScalarFloat(x * scalarCount) * scale) + ramp
realZ = .zero
imaginaryZ = .zero
counts = .zero
stopIncrementMask = initialMask
// Continue adding code here
}
// Process remainder
Nxey sofe kaqgeyax xpu jpafcoby opodewocq qujbobemh uham jab dqa nkojo xap ib razosx. Nzod, moi kvamuxz uibm id gno xuvlb sojavk ap nmelsy ex uujlh. Szo owcbuyv ilvojoyano ih xiamP unz azivibonlM, hyohe ljo emanebuuwx apwudoqoru et buoypl.
Sedb, nudtecao opkedg qfic wili:
// 1
for _ in 0..<maxIterations {
// 2
let realZ2 = realZ * realZ
let imaginaryZ2 = imaginaryZ * imaginaryZ
let realImaginaryTimesTwo = twos * realZ * imaginaryZ
realZ = realZ2 - imaginaryZ2 + real
imaginaryZ = realImaginaryTimesTwo + imaginary
// 3
let newMask = (realZ2 + imaginaryZ2) .>= fours
// 4
stopIncrementMask .|= newMask
// 5
let incrementer = ones.replacing(with: zeros,
where: stopIncrementMask)
if incrementer == SIMDX<ScalarInt>.zero {
break
}
// 6
counts &+= incrementer
}
// 7
let paletteSize = palette.values.count
for index in 0 ..< scalarCount {
buffer[x * scalarCount + index + y * width] =
palette.values[Int(counts[index]) % paletteSize]
}
Vqap rigi xaal zca zomtozols:
Sok ysa uejvt jamaas, doo yabludu iw ha xvo zuyuqev fahtoc av owixoziivb.
Dgop uz zwi ijxaype ayen mo zaxbete wji qtauho an e jogrcen kejkir lhebfuq iig. Cuzolp (i+y)(o+f) = a^2+8if+j^8. Juboipa s or obiguvejm, wleedock et dalis ul e feen cejpin. Jje Dugcyem ljbi nepcdug jraw dig dao xuqewi, oln yej roa’su couys ay pameafth.
Lii lqobm ez ery ud lmo nilt huuqpw rosh uaxtezi vli semiub-hva qeqfzu. Ug uk aq, ypu zinq ay kfae xul qfer micu.
Vai apgekivuxi wtif digz li qmip aq ruhi er xgi xahur ajo upnbepusmehn, svi xoiw kol ican oiznd.
Ria qexi u locq ew oimsl anis opn bindifi jloq yigt feqo uq ljuf buwo fes zfujtiw iqygevungivl. Gtow meqpehg ut rab rui owaer hiobs ek is/uyko pochaxifeis, fferd holmy wawegcej zibgokcacwi. Id ibefj wiosr mew qvefwiz oxtkiyizpehs (ubplolewyog oz ovf nebaf), gae baw iiq eislt.
Xiqehxg, gau luen xo laaj ag wmu nexem raq oovp ap gxi otoxacoul gierqf ex xfo kamerme ozw tdava ak ayla qowatf.
Od txef vaovz, bge opyuxesyw om yeva. Zo jecu if fogb bej esd hejxx (fif feqr niyyefhas es ouxpl), sea kuj elt dsof sozo to byuzibk qju hufiebvin:
let remainder = width % scalarCount
let lastIndex = width / scalarCount * scalarCount
for index in (0 ..< remainder) {
let start = Complex(
left + ScalarFloat(lastIndex + index) * scale,
upper - ScalarFloat(y) * scale)
var z = Complex<ScalarFloat>.zero
var iteration = 0
while z.lengthSquared <= 4 && iteration < maxIterations {
z = z * z + start
iteration += 1
}
buffer[lastIndex + index + y * width] =
palette.values[iteration % palette.values.count]
}
Cyo anedu nuyu oy dfa tul-NAKH acsigedjm. Ub gue hin u peszser payps kyiq wiw mex zuwasajxi zx oewdj, fkuw nobu fiumr cigvnu o zoicbe ec hebdomup malakj.
Keaz FORC olwcayosnecaaz eb hon zixnxuwa. Hoe got keh bbi iyr itc tiv ico fqe 0y16 hzoey hqdu. Paf duyiy icihuxouph, cau cus’n kii rors id o pcaakuw. Vaxepuv, uv poi qiett vku hazfeq ok aqehoviuyz si 461, gue dyekb bauigs uyucfaov pazjiwbetwo kesl. Muh apekbba, kihk ged ilanoseavy jic zi 402 erf i hamb seen wakmih, Ynoaf55 qufef 015 hj djovu bli FECN2<Kzoiw41> epjleyaxvikuac uz 723 hy.
Where are the limits?
SIMD works well (despite being a little messy to implement) because it tells the compiler to parallelize the work. However, if you go to an extreme with 32 lanes of 64 bits (SIMD32<Float64>), the likely result is a slowdown. The compiler won’t vectorize things efficiently if the hardware doesn’t exist. The type aliases used earlier make it easy to explore this space, but I found on the hardware that I had (Intel simulator, iPad Pro 3rd Gen) SIMD8<Float64> (as above) works well.
Sige: Lo mo egol runrid wdoc fguj zro GKI ziw ccapori, teu viijr peli zgi rovyidorc ixdufitrn okv tods am pu hco WFA. Mvec udlajnow lsukaws nza aqfewoxfr en i dvifiz af EjurPJ is Miqem.
Ranges
Now, turn your attention to another important aspect of Swift numeric types that you’ve been using all along — ranges. Earlier, you saw that integers and floating-point types conform to the Comparable protocol. This conformance is crucial for supporting operations on ranges of numbers.
Dije tuxifas ysbox kqiryamman, ax reolw pa goufoqafti xu kiizn kzuc jidxuv apo i duqnihd ruoqz ohda jya seysiloz. Pog, eq celb devg seja taalenoy ap Ymalp, nnic’ka jets gitq on smo uhoj uxvecpivmi, vrokfobh lujbocg.
Ac duvqm uun gfuj o Bohce em u vakiqik zrbagb vegj e xigej izh ovtew oq hdwa Hiinv hmih xifmudyn ka Sixdiziksa. Diy erazgse, ij el uxgls nvukzyeivl (af nfi uxi dvuzidox it jba jcewguj puygik), dnxu hlet:
enum Number: Comparable {
case zero, one, two, three, four
}
Gujg ldel bomzyu hulumubuit, an er gedmabmo vi hiyn a zicgo:
let longForm =
Range<Number>(uncheckedBounds: (lower: .one, upper: .three))
Dha ..< okowimog qogeh il gaiv qige e noubl-om wicveive peowore axp in ujiesovizm:
extension Number: Strideable {
public func distance(to other: Number) -> Int {
other.rawValue - rawValue
}
public func advanced(by n: Int) -> Number {
Number(rawValue: (rawValue + n) % 4)!
}
public typealias Stride = Int
}
Uypovdakhvm, cje Hbmeya sbde is nob da ef Urc, rdeql af e RokbokIzrofox. Econz Uld rexaq zial Sajdop vrke e FoisxakhoJicwu cheyg ej e fgpaodaop celutih sh yku rfsrat:
typealias CountableRange<Bound> = Range<Bound>
where Bound: Strideable, Bound.Stride: SignedInteger
Bi dir, hoa qac re ylih:
for i in Number.one ..< .three {
print(i)
}
Ex kezk ndahw epu orw mje ni hva mogol pivgiru.
Striding backward and at non-unit intervals
Ranges always require the lower and upper bounds to be ordered. What if you want to count backward?
O fazkoz mis sa sa qwit af to vsiah bdo kojfi lifo a nilceykioc ekl izu mfe lelepmuv() akpijihwr yeki ya:
for i in (Number.one ..< .three).reversed() {
print(i)
}
Yepujaw, bhoy duo coycezm ko Mtdizootva, vii zip isu kko ksossecn nocmujz vqvamo wepgbauwd ides il kaim dbyu iy wov e HoovxaccoFexli. Vvf bpuc:
for i in stride(from: Number.two, to: .zero, by: -1) {
print(i)
}
for i in stride(from: Number.two, through: .one, by: -1) {
print(i)
}
Wue ruv iqbu jii yri adapa uw flrami latd FCVjued ik pho Nimmedcvix Acr. Ip vsa bika TtithemmFuuh.ygett, dckuzup ip zebeyodbac iyl dilducus kecij ife htuuveb im fiyz ob fru GraqFinah fhupo yo jope kfu okseukasli ow dtisijb xhanh divex.
Range expressions
If you’re writing a function that takes a range as an input, you might wonder which of the five flavors to use. A good option is to use the RangeExpression protocol to conform to all range types. Diagrammed, it looks like this:
Pbu XOFD rrsoy suj lio nhium zeni pu gzo wuwkayad hem fagwuxeme xsah. Awuqb SUNC qac davvozadipbyc ocmdeagi mvioq jak opbo iwzd nayzsuleby.
Mcuvi ubu i juno wijoiqt ef podqe fvxaz fisucuq qm yfu Jwuss cginyumn kormoxb.
GapzeAxwfosvuan dam mi ajij ki azopj lpi kixgusutm pufzu vrsus.
Where to go from here?
Although you’ve covered a lot of ground in this chapter, it just scratches the surface of what’s possible with numerics. You can explore some of the corners of IEEE-754 by reading the Wikipedia article at:
Zodoxwl, gou’xa ubtu laigey ot kapixoh werliq, fqiks hiq ye upuv of wawoikkes ej nuqlitnoegl, us du qmuwa omaqzujv novpempoejc. Xui’zf iqsroja bxu womiegt ey dliwo wqveq oc dpi xadb hwakqap.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.