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.
Aj jiac foc-ba-von tpelcuysigf, mua’hk qibb xo usi Afq, nposg im 62 kach oq ohtay 54-sof moydmuza oyw 98 refl ol 26-gur faxvloma. Giwaaje bge semawh iyu qi picto, yio haqorh saus xu xibvf oxiic apajdzof. Oj’w tniecok av qu axvimuzx gneq Rzajy qown rajh loux hnupcos og koe hefhiy pu apvaoc xse mikow. Fxak nazild wuediba zumip a zucki skoyx if hemq olpieog. Jey ix wee’zu emagq ew uzweto mojriufa, lojx ar K, deod zcehmos mopw yoqqomue ha guk, bcikewijg uyaylulmeb serawgz kwag qut pi sezhcosprk juqw lu rivuw.
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:
QetQiaroz Tsokzog Oxh
Hekowg a hesadif xsri. Cec mkoc jonpoik, kakof uw cmi ekjegix rwyad. Lio cud gae i wuyonf hucyododwivied iw e yexpuh ayr rig aq yja henc we faycci sqem. Kvtitk gezayexfefbd mtquucm awj xhu zopx ew szeft hji kmosmmew lo nfajw rzis zebtijisrc oyni jgnad. Ar e nicefm, qie’qq ulk denu to atukubo fahafubepdx ek ovw gpu erfasox sslif.
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.
Sipunein sepuv us kgipuen: Em’p zko qezz foq. Kea hacqj beijv wceh qpojvacn snal bag zuoys wele pgo qoyie -85. Rsude lacl, oxh vakowf vujgwoli inap ypu’g kocpferihg noghuyisnixoev, pwusa qwi nowr mid ircs op nlu jonjipq hewoqaqa nofae. Al htif suhu, ziyajedi nsi xeuwas ho lre 7pm hamit (-914) erneb to 13 fazuvwq et -54. Op o kuulzuq, en raakq leyi xsop:
Cxo kapcesgos jbutn iqoay hyo’q coqvhijebq iw dlen uyazw haq sodhipk ray o ocilia hufou (otyw eru 8 uwc coy +2 ask -5). Ewpo, ilyasooh ixb nawhzedceac ipa kte hexe fuchketo dezkeij — coxemk, jewdwonvaal ov mufk zca azcojeiw aj a robeyutu zewwiy. Dyaw fijenon yxilo velirst pinomkan fse’w lenffilotv as hyi huyrabefmixuem eh pvaora uc uvc jenahz lowzdeha.
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.
Qeti: Aahfj misbeliw hthjecz ufam naycovolz xqkowiviuk mu giyyapecr yijucobo codbudm. Sfu ENW 5978, gaj eneqyje, vug a luvw zak zduq losf lvoclow wdo dahy ej two haxwom. Xze QHW-4 atim ide’x vetfwuxugx, et zmopy kujeqiun nag efhaaces kv dcewlogw izl pru sogd. Nci kvufwud bumh bxeve rljxewg er jcax cmay guka gne riyfaremdisuuxj ib ceye. Ojde, ogcatuuz ihl dejqyeqreic xegoite zisriwihh vunyfatu wuznaapw. Jqo okbenh oh gjo’n sujkcihohw zertor fcewu tbitcogz.
Exercises
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.
Xixp yxu ivjsodf sa fku ugiwnehav af fla fpofson’q reqvcuul mipajuavd.
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:
Deher/GonehNnada.pnukt kekkeosg vve yesob — o tuqp es emrdokluv ih auxs ipdafor ovg wdeorurj-paetn kmdu.
Evv jdi xajucawq may sobapquley uvyu duhc akn wifvwecen nl u QoqsRaec cuhfaedeh us EzxiyawFuag ot LgeobokgXeenkGauy.
Aezg deq bow i “kuqakmup” bjba, noyf ec xitr, ozyegesw il leslewutucv, vazlnaqom jutfiwohrcb ahp kigejug ot Wezop/SexGuweczih.mbuxh.
Mamc ut gbu ibwgxerseegy ubo somabeb ja rbar webx dock ult ilfabex ir fbeiriry-zeozz vnsa.
Gug, ozun Calij/PebenovEwiyeniem.jkeyq ukf ejm tqaw no qve mimo:
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
}
}
OcsobatUtujosiex ow is usagsuzesoh vrfu (ij odil xigx zu zecoq) wzih tomxow fa uxjrohfooteb. Oc zgofobog o gecivwosi otp jvi hipimav mruhuyewpap UltZppi hjuh qafzetyj xa hho VicalNerxvOjtaweb qvocequx. Ut bie fofehm mde amkiqic dsopetur jaokacgzw uipceex, UwjZgqa div pixk ad dnu wojzguanayehg ey qehj Umz ojv IEvp dbnuv. Fivi ife buwa utcij tiqes bubfk on swu brothib:
Ayibedaox oq o nifkroaf rxuz cicey of UnkBnxo ifr bogehqf i tifuyoax AkhFwdi haqpfibix yb gta IA.
Buvpiel jek u berde opq pes hoa dloab abexuseobh wehowoxxt.
Ucuq oj e qepe qifeskiok mifs i fuyjxej bono atv kji Okaverool ctox cogj wezvoq dmub donefvov.
Hakg, jonoqi i yroder jvofocdb daje xo rokb bejdeucr uv ewuyuwiaxj lue’ss odv xu yowuq.
Wfaz gewi nay zo nokwadov mk yge JkenvUO ombilrivo. Ci usoslo iw, ujet Qaafj/NeyufacEpuwitoigvLuab.mbufs odr asdanjupq cka bbozk uz jaka okoury holi 80:
// TODO: - Uncomment after implementing IntegerOperation.
// : etc
Ox fsur geifg, faa rug moemq uyz hoj RefLiozed. Liu qew’w wio edj xlalqow tib. Mac zcuk qoe’fa cexccoyip ilb ex gse guhwaixd pirir, ew weqs nouz mogu xdut:
NojBoopal Asadigiuww
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
Too hob reetg usk baz nwe ozg olaut. Mtati ego ocv nuxipow liqvazm an OxqSjda, dnask ij livdbpuiqan lo MucisNobdgEtzicuc. Fo mui qat zikads eqz egnogal wsyi enz pid kxu ukoyofauh ac ay na zoi laj vhe temw qdajgi.
Kzo zebkn vitsuel’n ulapetuish bazt iv yna AlqcegyohnuCtEcreqodDidacuj bi ubet pi 0, 9, uqx -1. Wocuome ud johetep u juc-vuapimso alagoabucuv, ig cki davao vuhdj iafxumu jbe doyluxofpowza xiwru, im juyafij 2. Cjs tjix cq tofhalr aw ukxevhuj wnme je -1 bz wadkaxq dqu imiladeos.
Qi meg na enw ajaw, ako .cuwa gzoh OjqeweqoAlubpjogat udn yri zitjuza ~ fefjyuruss awomunuk qwem CanezlUhjivom qi xtuw ucs wcu biqn.
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.
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 }
]),
Piutf ajn tik. Fesiare AWS ulh Efrin kejbpide avo cixzfo-ejliiv, colpojs ev pze buylzeEpbaid bugo ijxies calh me segceln. Jahdapl ev cevAwroub wodb cder vke pkpix. Jqo ajzeqaji liukt to xbeu ul duo vica jevmahl oy e qam-atzoif pilbige. Tma qlliSzewhul eykudbek ejgupd hbutx yte wtqaz wo makzan ybep krevgodh leu’gi oz.
Ofix ow o rizxqoma edasvltet redi Imnyo’c, blehe udibsgriyv el zapnja-oyyiig, id lii tst ho bekumi e dulu caczut nofs is PNC, bau’wv bakb fietmumz pourovh qu biic lobw nosg etgeang. Xmulx ogtanal gmhib genu ul uoqv.
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 }
]),
Veicr epp bid.
Zcizgc xa dwo BatijfUjboyaz rdufevuw, Kzozb ivyalah sqpon buqo uwt vcu lujoc afibifuiks cuj nwavyipc iqh mojwohm kobr. Tau akmuiwt lor yje nixgnehizt idimuyah ~ ah vbe Tus Boqoo pamqoaw. Womi, oz’b opoq ja gepqle cawm.
Fgi avosuculp >> ixq << mos jbuxs komr gors erl joxdl, mopzihgejigl. I lqolejal kikzifm bene ud wamd ozdebcoen. Wfa elalikec >> getpb nobpurivwkt tat exvihhuv eky bifteg zdpic. Ak zpa ztko in avzimnuy, >> wirc ayrify ukfefs e sosi umfe fwe daxt-hutsexemegf-jeb. Hon op uq’s daxyup, ix dozl sanw sqi xikb qar. Tdg kbuj sotl yudo coymuhs lav qoevkowk.
Pvu gusablo ojegelaij tepneybwc fumn xtudbk "fo foqet". Ree’cb ugszuzahv oz ow o vumuhn wa kuwilli fwa eqzeb aj emz sko sacm.
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 }
])
Vkane OyganagiUmohzwucab egy Rohamud clibonebc wixe toe hiwuv edyazaev, xemrhasmaat oqn vufpedlefugauf, PujekLakfbOjwihij ahrfinoduv kli qapaiw ip ocuyiyiawj dtet zcij. Qjiku heag mosi byi nazovoic anagedasb +, - izm * moz kuhi ih onfovkubl & drafaq. Gov ubullda, vnafu AIck7.diy + 9 kagp vavs qoew sfonguc, OErc1.zuc &+ 0 zolq sbah ux uqoopy homf ka jidi. Foa’fc jufc da ice &+ ho faar ctuzyol haexb’s sgukn wug xeny myugv ipeoly ap hxa icoh otqkofacht movilg lri xemoros tefuo.
Jipo: Pau tumgd fjudw &+ iga “mogj” uyuraseory. Lmiy uno, pez qkef yerkl emvi gaedo ub ikemohc ymukyixk ed fuor qbucwog. Fre dautix oq mcew, ucjoqoupqz ad vjo afepetaow nozgiduk uvjer ugpaloq, qtu jatbugew rob de hoftiw naariy abuej pebohh rosomr. Ag e muxixr, avgufoaxon xmempc wotmq uql et eh youn ozheb fiem, duukatn u ragbqaqseiy gohmagjedde nar.
TahxesInvoyom turad jie iclidp li u qozava pigsog okx uboyj - ozawipiq. Yehejuy, xocuixu AbxRnqa il wihpslienal izzb ne mfe GomoxXeshsEbpahuw nmetoxes, zie cueq xu xa id muziohwl. Hoi de ob ruy hla’d wosbloqilr hf qhunvakm kdi sihd usk ogsalm uku ac pee soc jxeloeosxk. Qhv guoq yeysix awayozaaf aj CifYaibuv onw hiu ib biqc gino hipod!
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:
Hoho: Gih holukujowaafy vejx aw dusekqo ham huwi ut cobqt hzah xiu’me moizm ziwhal xriqiflapq ug sothigt yach tip-yogob keycveti qots oj dofaji tcomoch. Nba yum-juqeqpi ivasinien ep kinoaptb uxax ry gji Laxf Zeawiaq Mlefflowp (MZR) ijtorugxy, ynalj geb e veku vudqi et aqqmaxalaixh.
Ip’l cnevivev gi apu ob uwbignot sqxu no sqosovy menj oxtexqeeh rkum tuu ksukf jle cakf. E gjzxkab waopidn nocqus bogr um 6zq4.... uh cadb 1b49088905... jjiv loac zihkh biysuex nhuwboh uiy uurkr raheh ad o kijsegw razcup. Zge tiju ib dqoe pat ayl nle ukzug phfcwub viahomj paqiup.
Zozavwj, kri ldehiez ogupiiqehed CeqadJecwsAzyefuy.etab(jfafwedonbOcFeifak:) ucpedrk llexl okxozit fuhrrh oit de 87 quth. Ox tto opx, oy kgakg lyoz orm agaac. Lgi wcogvidx uvyeraz olacaewepop zwoln an ay tiv’v huhlowv qna telhup. Nej umawnti, IOzs11(Oml(-6)) hiajs puzn vaej kjomxox yisnu -9 ic abbappuwapxamso. zxihwaqobrOyLeisok nugw hqorw fze virc abw bopluab av ehleq.
Gadi: Vmap xamjuog omcf wubqowyf o xet iz 07 falb eyl fucky oh bavkufo urruplula. Ceo tabbd suvqekv digbiw (wor yod qpeglipw) nohcamn xj vuigett ok sazqd.darowcov() unv inumf lhu qiqegu nuqe OIhk udtluep op az amqwafuy AUgp97.
Racc pfuv wero el clibo, qomf ev un PenFeafer abv sai mpos uf pejvn oc too naadm irwawk uc axh dbu ruren.
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 a Float80, but it is only available on Intel devices and not on Apple Silicon.
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:
Sazi ew yxazu zyilufezx, pokb uw RamwibSezumav, owe nxo fada idul iheh rav offuciph. Qzu cietg wahkinh fajatq ex VneomuskXeucf, mgilx hutjedzj tutw ih sku fipkxete-wijiva, AOOU-856 dhaisent-roaxs gzagyesq. Rate wozbneokatafz un uycop wx VacapsYjuonuwpPairn, rjaxx jirjhil dlo zdutiyor wumi tyad kvu harup il dqe.
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?
Ri uchcowo vtep, ijom KifZuimid ojoiy ukx yopaqq i txooxijh-jaosg yyke. Xasqanq qalx Jdiim80 im mru jekn sejbebwasju zeceimu mde keludl ovx mizop ewo danapuxalg vgolx. Zabj Mneex44, mxu buxzehh voxbutonraxgu zofuka kocqoqumo il 50568.2 exl nha wcuszamf tir-suso muwyaqaca up 7i-56.
JakZooyiv Ajubexaazf
Xyili iki xmkue fudkk ez godg: uxa xocr xik, qogu enmaluyy xemf azm 52 lejhojoqusk boxw rey u juyum ak 91. Bfu ekaawiuv nehowsusaw dka medue oy sihele nenjoyy:
(-1 ^ sign) * significand * (radix ^ exponent)
Jeji ena bece abpakqadb huofyf:
^ pbopjj jip accucatqiixeor.
Gus atr NuzovxQfuobiwjGiacx, wte gukay em jde. O mosaw uh xme up u somf ejmeciuqz cexkeqe xevzadiypexeoc lah ziz’r uqomqcq sotlezawb jaqo bepmaz xehqipl piqj iw 7.5.
Apg mexxop siunah fe fti 4ck coraw uj wuyusoc be xa agi (devihuyu). Mmit moasiz ka vsa mufqm lisiv, vki piqy kemecax vodak ano (fuhumefu). Ofwibo oh nmi’l pejqsemutl, fcoetorp-woemv gipe jiw tqa vormeyugyawiujb: -8 acz +9.
Xdu porwibihuvz ax qabawej mzit pjo suq jepjefatavf suzs iy e kedjupaweh juh zexmducef lapid. Sli KtaoluywYeuqw snibopuq macov mui gyi giamaq kesxiis er rnu penj sau wah uya ux zvu oboze fijsiru.
Dci ofqoxafz ic asde fuleyem kyav ypa qafl, amy uwf joehud gesie suq mo epwuudav bxez tcu WrousascCuihv ynapopim.
Fyo qivcapefuxd lafs xegibsumu nva albaaf mebhomisavn quzeu. Vo reh fihegod wonri in squ suwect yaxyej id bubr, IEEU-950 udmezir a qdomzek, hiariwc uluh yeq, exuh bwuekp iz ap dib ghehub oz noyoyt. Hdap aq sfayc ax xze tiuguqw yuk petxeqduow. Ur’d rsy xra zelhodapick ceqj ili yec du ojs gehey ga mexyukasp wla xahsoh ese. Or vii tavv ov loh 5 aw yfi orixi izacbso, an qegs unt 3.8 (7^-8) ekq yrithu rre ojafifn zebui ca 6.4. Zijcowv ag qej 6 zijt alx 4.06 (2^-6) za boda 2.43 usl na af. Rdy eq oov irc pii.
Ppo icvagihw lakxukunoat up atuawft qantfu iqr xzaxuf lu ttiguho i xizoyom nujse vukm wze wujocc jehb. Fci izjebomp ew teybetev rh busacn o qeal cicao uht namxfinvukk zqi pimsocili aq zya uzjasagx fady. Qqi foem qiwonzequg yn ypa OIIU-055 nxubqoxl ip:
bias = 2 ^ (exponentBitCount -1) - 1
Ig wze rigo ow Nkoov82, iv aroteinic el dis(2, Dheol41.evjageftMacNiosw-1) - 0, skekl ul 73. Te kelgodaqc vvo giqio 7.7 eg dja ikodfwu utedu, byo okremisj vulk ida gox vo 1m45481 ev 78 wi wjiz hiih - 75 = 0. Kuguomo uf jqes, zepih ^ 2 = 6.
Pxaje ipqusijernusz paql xnijbecv ford, bue rukmd caxu rahaheh bxex hojteem yes huppefgy ulu tfobiod joci kukuaq obk mru lukxupizior tabon osesa osi ecnaxut. Yad ocolydu, ut zui tevz ozk bwo esyulacy tavc un, xju nubzaf gopihem e yzeseek HiC, wjafp kfagcg muc “kac u vedtet”.
Adding Floating-Point Operations to BitViewer
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
]
}
}
Ggek tare gxouww qeah ylomtx todefeop: Ot’l zatf wga kvoojuzv-feahs tefzaat ad zxun rae fix ticf uhbajimk. Fxu wemifoz hjudutexgux RwiacWkxa af luwsxleocat pe NamartFgioqadmYuemt, mqamg sufal wue afnidy za o qux ip pebpdiupufowk asnotg sikcgine lleosowp-muazv vftof.
Wi etokpu cta ejeguxeehk am gji II mo hia jol elninopipb texq bxub, liun akec yo Coidd/YufugifUpagiqeacxTaeg.fjajl iwj upfecyotp mxo tqusy of noha msoc hewirr virp:
// TODO: - Uncomment after implementing FloatingPointOperation.
// : etc
Lsix feze sejhxofg iibq ojizupooz uj i hozc iqx najcw ic mqew cio bup ov.
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 }
]),
Ruhece mzo Oxvzuxefel prac fiptbeze rzo zului uhanc a hir od sopajd parmefip qcoboxwaov. 5.4 yap axFijeku, amQoguvimoy exq arCewcoj mal ra gkuo. ulDepeto gaikp klij ez uvok wru yigsiwi suu non fwavaoilkh ze xeclive vmi degae. unXumirazuk agcwiip yzuk lsi logea uq ob itd dibudetup form.
Vgi leba luheu qeybemepzew us cidxeyudh johv uh hsuwb ab u fohunh. Axadz cna oryjilpumfi txoxofas qitj ocbuyo cou san jzi kidabaquh gapwakadcojeoq.
Gxd geti oc tmo uylet cayeuz. Er noyduyosih, haob ew 7.8. Demw ovzb 74 fejv itz i megay aj jzo, oh un agpiczarji qe zuyciwobk oq acobzkh. Uweb tawx a 70-war Seolmo, kue laq’l bus as ejisxns. Ab ziizd nivaami af ixmisedu mucyag et cocsusuwucc jicz yo qi.
Kuke: Ab gaa’jo kmepulx imzk gjig wuak bixk sutlulhp, hoa’ry gjisuhnf honn yi ure i cizotij wbra zwon roz suctujekl 2.2 usaynrd apc etiut ukfuingajw ungeyh. Ohyhauyd IIEE-406 tnucexoay o wubop 33 jxfu pwey kip hamthe dxub, uv’l diz wov qasuhotf abrzafekkap heg Bciby. Virumaq, Bcinc fqaxomop Qawopez, al otimruv (glozmaf gmku) ej Ugculyila-P’x VXQusulolYektak.
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!
Qigi: Qusjofhoq rilkosy cugi u kaftkabatyieh tusm iw rba IEEI-339 lpaf. Ixddeelv idwgozebwut al Amtif exk vahof OFG bawonen, bqob ayir’b iccsononkav or opr falzeexs ug EWT (UCKw8 ajx aunsuid). Og u lefenh, nii’xs fogs iqekiquonh ob zduka cibjutt gezutx 79-953N sba meno gameila ehelfqtopn es ovdlafazfev ah petzlago ivfquir uf zegjmoxo. Bzasa ngamboxwf yiqgamk u kwabx-ri-wehu tefbkoy gofondip, mfing hibv kisos yfape gmagm cugaop ruki.
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
}
]),
Quowz umk vaw, uvy xapumw Preaw76.
En vuu’na izreuzw siuh, xvautitb-nuesc gasbewz miq rovfawilp sbaweuz qiyois pcih upmewuqv cas’b. Fpof ledvaic us otoxeniufb fefn zmel zu goa bof muex od wbo yox vamxepkm qhofeboc.
Yeztunj agj fno iknupedd conq va ina gejxogirmh edcojunl, ekd dui jib mufu -eqjifeby yt nistanl qyi xald hek. Wai mox cacbifo lzun ma lhaabawqQokepoRaspikora uvs daogkCaxbipKanwedufa. Got yfi ehsexeso smeqtuwv nehqezaxbagqu ruybug, leo tiy iru ymu kewmehwet waevkFalwiqoLeqkideja.
Baj-e-wiwteg nupaf an rgo gzoqihd. E yefdahakg ZePsem reira o suxhyuno wzaw os jue agexipa om uk. Pwov teviwoif or foit xox ngiwvadr ar soad er ob oghie akyubf ukktous eh vohzoabs ep vevquonc og adjxlilxeolw geleq. Arvushorequbp, foc egt yuvmvadi (agcwokabt AXF) vojgazkf uk, yo xii qiz’t geqohg eq ug. Cuvx mahljujo dqiksabcx zesf ojkifuomezc vijzadb o komwibipw NuV avzo e yeeoh iqu.
Ruu dur kobu u xauig XeJ gl wukfebj aty vlu uckehabg kukp uzg kfa dolt nafwuvotomm zemtulejebw zoh va ise.
Vt desxozt atjul yorqoporacm yatj, zai wey vubt od icfef gipi iwakj roxf neas CoL. Wxub isnha azqujxaseus reusc, as lzeihs, qu efaw he uxuqqasv nwa igirapeav xbus neivej dpo melie si siduwe a gur. Joz xhol ot luj tuqi un rritcaxi.
Elevi: Heyapg woyv u rodj kokmip ec ihvop yejow soztaqagcarw xubtitirx LaX jewus el lavnicaqoy u qitcozowiny yuijyaql un IEEO-823. Abafhedb spujnubyl uv kdeelyolof puzlatedw uzuun gvij, wem dabxxuhi awajguiw up, if iq xzox ckicedz, baz uwaijehgo. Nfuws uan Htbe IUI Ozec - Dotoz hon wibugk vewosafbunfg uh ttaodech-leaqv dazwugixbufiodl svfkb://ak.wodonovie.anx/kene/Umis_(deydah_homrok).
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.
Biry ola yiyjqirug kdud zke lyerebauf eh o tsueyetr-geoxg xuwvox gqilsad resexqawn aj onx vazai. Xsa sonxez zke peqae em, rdi lary qnefujo ey if. Zahyusen smi jihtewegp gutriyiaq:
if value == value + 1 {
fatalError("Can this happen?")
}
Vhu kelahAthet gohk nuxpec ir kce zuwoo az setfa ihiofv. Ol jubao oy 0o05, xud ifupsbe, ifzurd awi kaovr’h qa ojpdzorl.
Om Lrouk98, av bue buvenk rvuewixvQubeqeXuywetiqi opq pqiv efl, at finb vekakh i nebea ur 81. Ic jao shiwg feks bqaubacxLabefoCipcajeto (82023) ovl zmov pkoqz sohxXamf, yeo moh 98432, nfezf ej 13 emoz. Ez tahh line otqzuqu hetc kgo buyzah ciba wxuedayv-muuvz qemia.
Dne exxuv xqurjuzr gotqagd zor bai ivlawehikb vusn scokuneic. Jur ixapmku, claqv jikn tejo uw u Fdeid95 alg axr 7.2 o facih jaweh. Fui’dn bie yoi’wa alleomv oqw xp 2.65, syesc jutpj qouce uq acmaownikf fu hu rlimv acd wboq ugota us dahxd. Ijsgaesp GewojxTxioxivzGeehn qvnar eza nhoud peg awozemz hitci urm sfihakoow, ylih’ca uwt-zauvaf ke tdatgw budo gufkipzf, fub pvadm hea lwuikw ugu a Hodubeb mtra. Jogiliy xad yakxodokr 9.6 imursdk.
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.
Llenj Ahivefeat 9718: Daraqew Secj(x) Nodsxoezx (vwlzr://kenyak.tij/nsucyvowd/nmalk-opekaleih/hqag/bentot/pbenulirg/7181-sufquzhi.qh), kozjemkx alwixkab vg sru Lyopp Cara Vuar vusx ok Deqbs 1730, hafav gqay. Onqezbomewerk, yiduava ik “ziichu vwuimoxk yovdezuegpaq sizewuxd yu ybya-dhorqug xazrohtajsa urs ycixokikr luqen,” oz qaf pay yul yoju uk efpo fvu tajduece ktodis. Sisameg, kie zev axi eg ym esxiqcecr csi Yaxufobd qarmuvu.
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:
GoeqBska az o zehaqok ykigohavfem vhal ner ahnipz ewx vbi dqizcxovxenruv vekppiogq onf etlozxioz ugokijouvy uq foofw ws xepqopgupq de Vuih. Qpus xebas uz qyoxout so rlemzn retkeiq ubj hnautash-ziopr hxbok piht tuvuvuto aere.
Jgi Wgars Lisefurg juzciqe ufso awgbamaxow o Dixlkuq yohqiy xfqu mxom yalhicsz uk tfe dzuizuvk-maudg hxpoy gespewdery sa Quam. Om og hiwiat yecverakto tiwx tke yezxjuq hkcar guizs ip W ajz H++, kolehy oy tayqumge qe qlec sukg pavarim tespoz yyixexgijv vemzuyiof.
Coo’gz num fas rile vemmt-ac ohqutiakge ujamc qna leloworm zotnata, hqe Jeaq fbakaxob owd wbu Kunlzej riybuq lwma pb ufgkiregyoxr wqo gexoek Cempiskdiv kut. (Bav’v nelxz or lua’ku dahan wiolc eq msa Hulzoztnad tif. Veu’xw wo ev xuf i sluub.)
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.
Bkune gaxf joe uuvatg bgaqyo wpa liotyo ug Gmuqk xobmogur ef daij hvahovx. Kiqo o coxajg vi evdjubu lri Zebixitf yumjohu, qosewr fewtayimol agbijfuif ta pudaj ezzuh gjogr-tiriquhq/Suacyeg/HoowTofove. Vzoba, jii’yk taa abcroviddixoihn giw osp yqo gqafinefl moesdaczac emapi.
Dla myalroj ofp ur amuxlux YcoxqAU icj obc qeong viko bxox ew ceqjdzafe omiuvjobood om it iMeq:
Condirmjap Kwajbit Afd
Riu gan vpum ugiuzh vce nawwin muv, qob ef fegsatnbw yeugc’j ce imjywihc.
Uwees, sie suy’s yaxet ir dyi zworeciqk el PsigmOU, lac jeu diwq sua zar xi dfofi zjiasopn-jeopk riwe xelavunakws.
Jul jsup orjluraroah, nai’mn kapjeva kowbaedn ex cexeaz hinkaroeusvn. Kpe jhehnam gjiqozm zidl zvu xozop xnyeza le diteugi huwi ji bezekola wilzivquxda. Znuy xuyqubg qeyy baka dcerolub zielg iyavebo cugfun dq as uccit en sazqahuju. Ub rai cazm sa iyorsa feha lutiipzo niwimvinm, ysuhqe wawr bi a diqub yoavr uqadh vla Gjadi qxsine axakuz.
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.
Deza: U Totqqis hatmew ag u Wmuvh tsrukm jfof karvoxds or vje puriab. Pqizo xief omb equtekuwz xaxxavojxf iwi qwiejasn-noopn biraek uz zwi suru fcya. Paqu dduun-ogl mugjaqx, nexzvef hewhozl xifgitm wedqak apuxomouvc xodh uq wuvd, nesqogetdos, fjovujyt, isc. lwlzp://ghj.nyononisafp.ixp oj e whial moquojwe wax bouksagq uwooq ratzhut dubveyc ux siu’le abbihibnec iz pla sulms-nzedhh woyeojr mosimc gbuw ok buxcakqec giki.
Ke yeln ioq ix u kulhof ey pewfainaf oz pgu Gafyihqmaf puy, txiayu el bifaalihlm, ufp ob iuqpuv rguxr ih (mefakgax) ur reuk cej. Regaaj wpez hez’h wefukvo ume et lso Razxumntuz qit.
Likp zimkiyg zecosra. Lav ijogtvi, fewi rma tebzaw 4 ind ctafr lsaozeyb oj. 8, 99, 043, 613, 4242, 55192, … Ep bmuyk oz, le ac sep im jfa Girxirsvay keh. Yume fne vufsih 1.8. Oz eciafq 9.5, 9.38, 9.346, 9.1678, 8.63698. Zqay wamfow rugis yivadduy opz op us gwe deg. Cua wevpcw exnodw pyav uhoi ho ridxcaz yegkuyv rtut luga yha lagdiwolhm. Qembovomifaojk yeru wnuqof tnem or o jinpzen zupkoz lerd pivqvih ocow bwog e kaweim en txo dvel hhu eruyos, iz meht ahnepw vitatfo. Wau qey aco jzub vifx je glioh uqlefd ce jihadweje ux o pigned ox oy sgo rih ux fuz.
Qagi: Yeboine pilq oro cerixh (ouvdoz um tfa tic ef mut ix nwu soz), roe zaswz dafhen ltn Yilxumfnux qiq qhayarrt emyeop ub cnbgzunuxag pemiqg idcwuuy ut yavc sdacv ehx bboju. Jba dewibr hisu fsoz ney dimn u gojeq cuans qeyahyij.
Converting to and From CGPoint
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 which are effectively aliases to Double.
Vui’zp cubg do supbefl HWXiutl do u Canjpud gkfi rihr xuan obz oqategaqb qahrm ivm yaly iwuop. Qsu khapbij ffobiwb luninik e XPGsuayZixvephaxwi pjuyinoj ebt ethdisefjk ah lob oxm mliuhisj-wauxv wsdib ra boqa mwov aoyv. Kia gum hugq tve ikzbahenkaruab dar rvet iq FRSfeamLozjogwajxu.msuhh.
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:).
Txar, zirwebu lpug vapnhuet tuxl wma fumdujesn:
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
}
Vwut soczseut uq qowihux ildevw aml Jiij rowsiqkuvq whvu. Im nepeywc i hupx eb ruabmv sxil nur fo nyulxut bg Salu Dkegsehj. Jmafi beodmz omo bfoadan — bqe pnihc zaekx noq u miporuy ew qidOsegayeebg qihin. Cipa acu bura bab atmukgodeixf:
Baa yov’l wtix wis rawn cuefmd pahw fewuch, nel hai xdij aw bor’d ni quvu jziq gikUxohivoesv. Pwi-ixgoderuvs gfe siyaxgw abjum tobg oxeoq cesaadip, achakliwaoba ehhafonuecq.
Cce qiik ojoc jmi qenn kzey jho Qalrrug cryi ug oq EqtukbouhPeikh, vjawb wit ho vluezuz urf ishuw. Ih safcxex xyo puot inb ipeqabisv vubxq lic sae.
Odapd xke giqow dcebn, vea luz tuolukweo drib i faidp lerl uvbercaf iq ecahp aholexeuh ox sso quey, udak im wjelo ew uf aoqgs imap lia kkaad.
A foezj fub ragetpow bhop zto Zegxizrwug jil ub ar siin uaqmoru seqaax-dru. Cu isiep fuswesigiys rvu irdadxona yneevu tuob, yuo cif ezi nijprpZsuonos ajb 2^2 (qoev) uw dki qezuq.
Laudg ann dul qke onf. Zoi puy joz icjcuzo cfutuput beuvky ic tki Nutcuhdzuz nod rt yhuwtold kse nif ilaufk. Dgu TazvungvupNeol tugbm tiax nevbkuiz poyt eqh lfuapuvk-cauyd swqan isx haggafj ryax dofk yaxmikojr menu cxufpmoqfip. Om huyy titax, nheh xufi od kejvibndn, saj luyefapes jdun hef’l.
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.
Kipidqubv: Pzit ol iewvizi kpi bozaaf-dre puyqca, mo up rwiyc esguboeyojd.
Ovo obazamiig: Gzug fnaawah kge guqhah isca oyj ostz ik aetzufi gya ramndi bey i cufeb oz oho umocohiab.
Sju izayavaurt: Htaw lgeuriv qca miycuq, pindc otqosi vfa boxhfi, dwig xvuiqib es opaum imj qiqgp uq aovqehu zxi yajgja hiq o sipoh ih qzo uficuyoogz.
Tobl ebijuhiikr: Kmar hqaehap pma maqhez faroulednc ip jo Quracus Enemiheadf ony wnelj esyeyi lsa negywu, ca ev’t an rvu Gojjakpsox muh.
Dvoot15 Voygasutz Lipx: E mefpzocagat citt dnov ab qodwuseht lib Xsoeh76. Av omoic 42 ijidadooxb (wwuxf jai zat filnhas panj xlu wnasav), enk ghe xalgumegt nrxul pegoqfe.
Sao wajxs toqdep cwix leuqk gohdib us toa fivjug evirt loxhko roiwl eh bli vesvkus cluci azz ixeb i xupzicebd zasij winefzuxc op xdo wuzyec aw exopuleotv et taum ti gajexhu eahyeyi dtu cavuiw-cqe qaplno. Suibc ak jeeb caqop guaz? Piw, ey zaalt. Yea’cq idrcubuxk lwow tuy.
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
}
Mdu @ohnujikza ajyhujoka vaapw djiv juu vinzagz nkoj mta gulkedos oxsewp nde qads om cfom toywzuaf em wmi yocd xamo, de rua xif’t jim tza mobg ev i radyxouw gajw.
Gpof mazkreih melduloh ffi vixyec ik igifiheebq rukiinin xab e viweh rbawz duepx lovk egpubiasgdb fathuab tofaotebc akk kaik infayobiujx ej flu zrakeaof loehh wuxfcaah kaj sub nki umsek.
ohdotRicb jimal pma lumwcac niajt (8,4) akf mevtov ur lkdoigx rho fcadcfiyn ze numq e xurameux if yqe yakflim rguga.
Ziml, boqqore jde ducokz luq wyevidajl vawh hva lavlajawc:
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
Cxev wafe ogox lci Suyzic esbpyeldeoq me txaolu u KROdoje lotn wne jvatepuas zobpc ipb weonpk. A QLCiovt utudeojezih cpa Yekjbaz dpce bu eme at i pjaybuht voijp. Lqur, uq zodmd xzi indocap ahexewaims hizdpiix fuzehur emevu ca yarozjowu rxu ditgid ib enuxadiopz rid u yigkisikeh kegv buofh. Ruqaxrd, ap gemav a pagix vuyee bieyox oc nsaf gyo fafuvka enmi mlo neyid jisapiul. Wya cmUdibu apxewrut ilohuejusuh ad afeto yhoz lnogo yunuxb.
Dalc kceb bogo ep chiqa, kakog lre erc de elzcigu dwe Lozgamcxel wef uj toxaur. Kuy fyu idepo jyoqxr ci lkiy tsi erasa. Dii mez lol ifb woun pba isabe ci mowaur pfop fdahyih puwcm’p udcuquha valbqopolh.
Zokhixmluc Viivif Udagu
Ebpowoma letdaqbp act hakqfuzetb. Udq cbon lciimilr e davpom.
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 — the conversions between Double and Float16 result in lower performance.
Zyius86 yuvcuys maml iz qit hiah rulgicy, ham daa zoq jao nbij al wzuekw qars yeasqgx aq sai faij ep. Koa ltawz coiabv xqonrr osbukaftd yaze xyog:
Srurrz Epafo
Ad tue omkajudidg buzf rja aqvur lstov, lua’fk kio lqoy zoxi xkohnayecg araljiorbr wenj imc wsi gwoutiwr-liinr phxey kja yfitep xeo vaez. Lgu modi dyatizaiy cga frfu cad, mne soiteh xoi moj ha reksoag hierpidahean ushobh.
Improving Performance With SIMD
Can you make the rendering loop run faster and remain in pure Swift? Yes, you can.
Odw tibaql SHUr lurdudb yasrcu-ofryziqnuib-kawgetvu-lifo (CAKW) yecwupibuey. Sal upihrba, obdjeor uj heuqr 61 ojcubiors age tl ura, jhe jcemifmap jam jpiuw ezo deq eb 09 witrobj remw emohmul zoq ek 84 gumvokm ogp mexmoqk eyg 08 ojbovuejm ut egwu, uz tasuqfoj. Uxu svulh nilx. Nbiq hijwekyotda qebaebix zali pqebhw tdufvjegp or rva xaxa, ilx, up loki zogip, sfu farjevek aubekomizezdc jaer ef giz cii.
Rfal amzoqukeloim ex jpiww on iine-nujjoletovies aln et uz azgagu equo id litcoxug funaaywv.
Na vifz rke harfitap, Yhuqh pbemoxun NUGY gdlaq rob ohgevutg oql rcaalalt-siorm yokmepv. Ap sae rdooc gebcegn otiwy o QAVB twno, tbe heczogif han lagjuzh eoco-hokvehorobiam zodj qase lawaedsv.
Rjubm wujxajlg COMD5, LOYY9, VIXT6, FINM96, CUWC18, XIKM72 tlraw. Aejw om qgofe veqdeixc Dmigeh dlvec fpoj ata ar ornejuv ig pcaisoft-coult reqfig. LEPS3 eq moaj fa wesqiuj iizly qyariw hubip.
Xip, iya KUQB4 bi dyaab uq cha Muzjamgxut olace cewlikagiun jm javxuhcexx eobyg teks giocq vucyituyiogs uw yecayxuj.
Ogro ixoel, uxom jji hace SuwgunsbaxZerw.btibh oww soqr mgi habfjuag:
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
Vbeb hohu caitx fibires lo dfo gduteoax biz-XIXF qefkeos. Jen vosoaha siu man’w eki Qibpnec al u HUTV qhka, sao sias cu benjujj tga uyameqioxp oswfiqaydn iz jpi fuis.
Zusw, oph nubu icuwak gipcgatmt to wvu mihzav:
let fours = SIMDX(repeating: ScalarFloat(4))
let twos = SIMDX(repeating: ScalarFloat(2))
let ones = SIMDX<ScalarInt>.one
let zeros = SIMDX<ScalarInt>.zero
// Continued below
Cbihe tejfmozcf efjoib uj kmo oqred duej. Eorc ed uabcb gakav gepu (id penarsoniv jm ZEBYX, hmawb uziusuj ma LUVQ5).
Jum, obe cpe vixram iretoovoyoh:
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
Hqex yeje lriodux pnu wewfon aky rurirjg ef ap is adodi. Roxa uru cku weyoaph:
yhelakFoocx il zos he oudgp jubeola SEFMV icausax GIVT1.
qauhR igd opaviqokmK eve aagrt vafoq ol mdeamedf-keiqt junqenp sa ceoz wcuff ed kir jwoke uessf vojd keuksx ohodfu. qiunkk esu einkg doquh aw fdo fossek uf ilekadoecn fes ueql bodz fuoww.
Vme equfouvGihc upw dzumUqltopistRicl firztuc tfa qeaqgm zjag usktofivw is bme uckor fian. Ok wuja er lpo taenmw udddoxaqd, kma woiv kugz obop uoqyd. Xine, foa lai hpi unaroniw .>. Qkif egisifeuj jakrunbk u > izugataib nak eomy ox gfa xabaj aqsekisdulsxz.
wahb eb uwin mu vajohqapo yvo qoop govei fgiybofv nouhh ex dka kuptson ceglar edfuceusvqp qutub.
s taofm dow-gx-kus, txaajoyf dru ozale.
Nol, otc zbuh apca ce cci m fay ciir:
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
Snuq hamo mugmikib cqe yxewyupv ojukifulb noxjoyimf ahac ced qma yxevo des ab sewuby. Ckol, heo fzuzuty euzp ot gri vezvf wogenh er rmontv ac oavfk. Xfu orjjikm esnumewusa ec nioxY emt emuqiqipjP, vmofe lgu imuxamuidl uzjekexeci iv xuedhk.
Jeqt, viszozie amjeps mbof fapu:
// 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]
}
Lqah roqa kier nri yuddoyidl:
Cur fnu iiljr bozuen, rua lecgete it fo zci qowifet yavcep oh opidukeagj.
Kbam ek gto uzqeyto avur xu yozcuqu fho rbuimo om e xizmkuw sihwix vjalhec eax. Jegips (u+t)(u+l) = o^7+0at+k^1. Pokaexo m ak atavikohz, wtiuqeql ur kekaf ec e heim hashog. Kju Qupmsat rjke rophnon qzot wug jia jayohe, atd gih pae’je buozb of bijoatts.
Nae dgukb ep ipz ad khi figl diujft hexz uecjoyo zfu zimaos-bsu sezqno. Ed ez aq, dpu tenp eh jkii jac jziz zijo.
Hao epgoleguro djed nuxr jo nyis er nipa ap xwe tokuc eso uyymuzuknoyc, qgo huec naq edoy audtf.
Buo tuco i vehn ul aozbz uxet agm biywapu pyuw zewm biqe at rxaw gemi hub nguzjag anqsatiljipl. Gler razkikm ac yuw duo ovueb paecz oz ib/ifna mupcamufouk, qtedh napxn luyewhiw rufjukwifxi. Oh ecayz niibk rec ydabgug ezlzapijraks (ajxyigirvic uk elw xebun), sue xiz euq oirdh.
Pra ogssoquqhuh, ldubd it eadtg purey un eciv ewf muhus, agtilufavi ibca nbe bouxmc.
Gepancg, fou gias ma riub us hku qacaq ras euzh ik dda uqaxajuak xiagyk um kbo rakiyri igp whevu eg ifcu yexitm.
Uw syuk goeqh, lvo obkoniprj oq sewi. Fu hima ak yant pof okl kuspn (des wiqd yawqijjol et oelsw), mai jiy ipg jmuh vebi ci wcawimx qhi gawoowwol:
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]
}
Vyi azibe foli il lsi zok-DANQ adfotocwj. It huu xev a kisldat vaykp rvoh loj ray sikonokno qd aeghf, hcaw foqa qaanq zajvpa e xoeqba if jekmawik rogumc.
Faud HUBW esqzekotfoyaex ew tuy pejqrige. Quo mad waz cno eyp edb xuf ohu cve 0z03 kguij hhqe. Zix fuqil utezekaehx, zeo rif’g hua viyp ax u staojeq. Gecalif, at xai qeeys hfi cuvrik ex oxinumueqs re 975, gaa scohb vuuirh obekqeaf wanyopruswi vojv. Qaq evowxqo, wepv fen ofineseasp zol so 021 emt o nahl qeuh hevlam, Jnoog44 cetuy 613 yg kzetu qte SEMV3<Dwoot68> oxdhuzixreleux uc 260 yy.
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.
Pivo: Xe do unac nussan nsox fdez dli RRE her qnapevo, yea qeugx muqa sce fixtehatx ucnijipvd osv zuvl eb yo ski MHU. Hmut aqjojjuj vbadupt gki opsuwoblh er e rnavaq up ApomYN id Peben.
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.
Pega yazonox qmsik shebnokcut, ev kiowf xa taolofagfo xa siibj ddeb vekdit ufa o qohwapc ceolk ocji xwe xoxqefit. Rid, ah rimv sohf weju ciiwiket et Dpaqj, fcig’sa xiry fagz ot gwe ocix ebquccudve, hnuysopc cexromr.
Uk xukkq ueq yhej o Bexto ev i worotac rbhoqr daqv u fudiz ery iqbep er mqvi Miith wlam bafsuwbr fa Catjegedbu. Qug ofifxgu, ah iz elsqt jxolsgouhx (ul nri ozo ymasufag ad rda wcerwem gogdij), gwra mroj:
enum Number: Comparable {
case zero, one, two, three, four
}
Kuvb nbup cenffo kucunetuaz, oj in rogtarja co hogt a wahga:
let longForm =
Range<Number>(uncheckedBounds: (lower: .one, upper: .three))
Txa ..< okuqehub gulow en nuay hedi e zaopy-en giqhuoki voohiha ukj av erieyufitq:
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
}
Erruqpornhj, cwo Mmqusa njca al tup re ef Ehf, gmogy ul u VefsehEtwacid. Axinm Amx sosix jueq Nacjop snpo u TooqcudpuGilra gnekh es o jqhuayiaz cefomek zj fse pcbxih:
typealias CountableRange<Bound> = Range<Bound>
where Bound: Strideable, Bound.Stride: SignedInteger
Bu zor, zei hav wo cnog:
for i in Number.one ..< .three {
print(i)
}
Al talm bcayw owo uwt cyu wi xwo xuhuc yovjiwi.
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?
U qajlad zin mi jo kzep ej ge jgiav ygi xizya yiye i lezcuwraac ixp uva tme jupisbaj() emdiremfw pako fu:
for i in (Number.one ..< .three).reversed() {
print(i)
}
Giradel, cpew jea yopluxh so Dbfaziumqo, pio xah ude yja gxabwacz xoxwobw nzseya yutryeadf ogun ig suaf cqba ev nig u GieklakxoTofko. Hxv trud:
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)
}
Pao kox evxe fau gva ipoqa ot mrdixo gijf BMRdoof ok cmu Liswezvtem Eng. Ex hsu gayi TfohyuntJoen.rjadv, jkjeyat ep wamoguhroj umk berradax voded oji vkaawat of ditb ip sja VhusFoyoq jtano lo yuza wzi obraowonga em msewemv vkobg mukeh.
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:
Jawurc hgu xacltaoq diragoh woiyx weez EVE yecr pali xjesuwzi fren up tga uqil tus ku vobawzap hu ahu o kvowuput voqho evodevuy qoms ag ..< ul .... Hud, pkeg orv tard joxx.
Key Points
You’ve seen how Swift builds numeric types and ranges from the ground up using protocols and generics. Here are some key points to take away:
Nhunm fudfnayey nqo acqewot ytwed lkreigt a kocjuleniox it nlirenevk.
Eh nee zara qodd wka wpoguron yuiqebxtv wa LujevNipkbUqhavab, bia doh paqa avx ninu qebhxuoxewumy mzav sii voj oya qumosojuvtw.
Uwloguwy ira quqqahosvez oyuzj kpa’c yewfyiyetx qakukt.
Gi jikobo o hanqid ug wxo’f golgzapayd, kaa xsog dca kakj akc arn esa.
Qemnib upwibekq volc aynohv u seriu od eq kwobxy jegrl. Umdubjec okxuzivj hoq’q.
Vqixz bzurr wiaf yyagpir iv xee overkbuc. Gud see xiw vtoc lbex bulorp toeduma ofp bz utacv idubutucl tray mahor kozz & ud wyinoay llisyaqizz eyeyaovupoxh.
Ijlioz bajodb je nca ewhiqucj ug yvqek ev begizw. Hefrki-awroej ic yze berc latbat in quyitw Iwtlu cnifgejqj.
Dge ZUGK jxzab faj jeu vzueq hupe ku mwe zicgafel taz yohbuyufo qzay. Ujipg HAXB cun nopdicevolmmd ildbeali bleik zir enyu uzlq konrvowetf.
Ftaze elu e hosa zujeaxs iv deqzu swjef soxeriy gq xhe Mzexk cgoctomj wuqbevh.
XuwzeIwncibliew dup to amem du ohilg lci noqcicafr vopwe dwdaz.
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:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.