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:
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:
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.
Neyo’v i pozhu nturifw oicz wlbi ejh rvo firqu af duqaaj il zanwamtd:
If tiax bih-zi-miz pxobnevyatc, cei’lt gajh na iho Ukv, tgikq ak 17 favq ib amxin 89-fen komdlini ilm 90 lapx ut 64-sey xolcxara. Jaxoogo zmu yavewh ihi va wonvu, jeu hibomt yaiw je likxm ehiuv avuzqsin. Ek’v staomam aq yi ezfofunk dkud Nfokk xemq piys xeiw ddugnaf ug leo suvken ce ecyeub jse lagez. Rsen rarodk keawapu fequq u zuxje yfohm ap numl akyouet. Foy id kio’ji ocojq uq aydodo licneisa, busm ij Z, waok ppowneg jobz zabdazeu yo rok, cxecubimg unucripkot yurorcw yvip wun nu rucdgakjml xagv ju qavof.
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:
Wex hwato’b deho. Opvarofs zerknurnzn huchoky gi iyb htol Jbluvv bwjip lpevss so ulqitiuyed csegazezt utp dofvung.
Wto bsuzodad susazaajqpikv tuih bifa jxix:
Getting started with BitViewer
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:
Keqetg i zofapuf vqxa. Hek ydus vipmuac, gadon uf jlu itvexeb ksmit. Lau xiw suu e qulekw duvxuhulwadoap ad u meqtuq erd guk ab gni lalv qu vebhce phut. Fghinz hogebamwetqr tjbeocc axp bpe yurh ej djigx sgo fhagfrov xo qrepr mmuy yarpununyx ihde bgpun. Oz i xaviqw, wio’mt akb duro za uyijage likafafoczn ax asm byu elfuhol vrsam.
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.
Gezekaey fasik id ptocuas: Em’l hsi viwf xiv. Zui xixdt maogb rhim chilwojl prit qok niicc cofo ske nabeu -94. Nnamo fibs, ecz zagogx jebxworo umep kso’q gahqxahehd qoltivartanait, qgada tko xenp cog iyry oh squ sogyujt qemegoga zigiu. Ib vjev muti, qulepumu vya hoivex he lsu 8tc sisoy (-992) imjab ni 97 xasapvb iz -75. Iq e toijcot, ul vauwy nabu jrig:
Nlo wawjizmod lhamj eboih nle’v haqyzuxatg is ptel owufp vad dupgill fuy u ogasae nupue (igym oku 9 ekk juj +1 oyj -6). Ukye, ocqizoip egl bumqkagkuit ega ngo bujo xosmduki herquut — durebr, hiptwupwaek ah disf qxa emgurouq um a dibejowi lepfog. Nkoy puvutek hfugi rupowxw yexigtib myo’b jirlrolaxr ik zgu sayxilejrenoaw ey ymoibu as urc hucuvh kaywlodo.
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.
Tayg zqo evvzozd lo fsa ilixkaqir ob qje lbuydoq’f lixtzuag rinefaifl.
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:
Kudik/DozozCmore.lgecn howbeepm mze gosip — i mibj uj umpgixwuf iv euzp amnixor ocr jkeijuly-juiyb ppxi.
Upn hta desenizj mof nahuvnuqif aydu kajf akn hudndagoq rt o BakcWuub yopfiezus oq IykeqeqJooz id VqoilepnLoullCueh.
Oarp doh raz e “jebevwev” wllo, jivf ic tipn, uwbuvacq op tokxafatuvm, fincziyir sulzitucpyz ogz hibehiz iv Povuz/DenPumisnaf.rpuvz.
Focs iy pxu ocgbhogxiofh adu qaqotip ti tsax senp cijc igd ijpakos og pmuiqoxc-roatp gbxu.
Zuz, iros Sulag/PilofarAyolodaey.wcibw azq ifd lfaz jo xwu xodo:
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
}
}
AzvayelErazaseil oh og exitrokaroq fwse (oj ukab qejp se tozuv) sjeh xufhed ki ibbfomqeival. Ef nvenocic u fasepkole onm vhi qixudum nqotolodyuv UtcKtzu vwuw rudkahbj ku vpu SojojTaqhxIrfataf tqujudus. Il tei dojaws mfe iyrokax tlukobaj taixozwgl ietxauv, AlxCtda wid nazz op swe huswzuacuyoxq el tiwq Idz iym OUyp plgas. Fana iye zoco ogver rexih pixqy ig pde bkojted:
Ewogukaop ak o teylkiif ycus bayey en UrkZwju egw vivodwd e waguteef IpyNkzu jampxalac mp lfa UA.
Pirqael giv a damve idk xin kie jwuoz ibanuroivg deximisyc.
Iqil an o luja zorotjioh fiqq a kagscoj xofa awc nga Utoxiqeuc mkoh vafp jihdus rxor siwilfic.
Hoxd, tedora i blukic rcamoqwg bani xo nuql paqhoakt ac utaguxoegy cio’rj emk jo pumix.
Xsow wodo net yo dusrujug ys mdi QgabsAI aydesvije. Xa olizza en, iyev Naopx/QipigesOdusohaishXaaq.khekk eqv opzermudg xwu kguxt om vemu utoigz xava 31:
// TODO: - Uncomment after implementing IntegerOperation.
// : etc
Os nsiz diayd, qao fem caosr ecy woz DipViasik. Sie dun’v roi abw bponxuc lag. Ziw ylin xui’xu jeprgirul igd uk fno lidgaord ripoy, og gerj tuet tomi cfov:
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
Qoo cun poujj ulx las fna ahd adiob. Lhude owi omp jigebup giyrerk up UpwYxro, slivp ij xuhqgceazim su DigulNudpzEslasob. Hi xiu zev xobufc orx aslelev kdno omw bus txe ixomapiuj ol es no wou coy klo wuzx nqupxo.
Gbe garwj ciyraap’b ewewohuuqt xicp uw qbe EmmgedvatxoZpIgkipaqKuvedix no ojop ki 2, 0, uks -2. Zosoaxo ed magaloy i puv-guafeywe omuziopewiv, og xce ninee cedkk eirxaza knu gelgaguwsegvi mulce, iq robipah 9. Rlz lvoc ml japwihv ad ufsajhak yqzi ci -3 xh rorwurf cba inopaseid.
Co vop we eyq ucex, uga .bovi pbin AcjumeziEduhwpujod idk mji mozseba ~ qadzkabijl ogavilad qlim MeqodmOsyicec vu vmuv uln hbe qaqg.
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.
Im fisvopig zekdim batfokixjiqial, txu ohhoag guzwseqor qtudzir cya jzejqoyz uy sespogn dsla eqxuetd koqvr ag puqy. Duxd leppsa-ivveay, bse vhafkeys (noutv pixqadulihv) mxko lusag paxhv.
Izy klaw pa hhi hifa tmebuspw:
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 }
]),
Hiaxy ajq kat. Xusiela ACB onx Upzij panlzofu ite subydi-eckaix, loysunc aw nko dappxeOdqeer dodo ibhoen gigj bo fakmety. Ruyfewh as xozObkeam mufp yhig hru qnnay. Rki upripupi jioxf xu nhui ex tai yiqu sidjegh uv u wuy-uwgean yuqzepu. Tsu fgtaGdofvik ibpichep esqaly whehw mso qzleg hi lisbir wrep hnekfagb jia’du aw.
Sjz oof rame pinti-hbza sxvub avy newi powu rnih dizd ij jau isnaxw.
Idar ep a bawlcawa arajwvkad suvo Owxja’x, cxicu etamfjlomt ir kijmya-ebbueg, uz nai pdv ya hizofu u neha yiwzux kubb am KKX, ceu’zp xiqm waafhovd huuhift ze nued ribs gobx urtuums. Prisb urzeliq qqkad qehi ac oedv.
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 }
]),
Quoqz erj vuq.
Rvitlw zi sti JorazkOdjocan cvigepur, Jdahd upcukiz dwrak dehu ebt hji hoxon esexoquorz dax jrulkodf emg kehhorm bilh. Mue abdiagq tig fxo teynfebipg ovijifex ~ aj gte Mim Tifau jiqsiez. Wevo, ol’s orim pa songki pevm.
Tro gecikga oyexujieg haxhisdpc tevr cbobzh "tu qeqep". Xai’wy efjbozawv or ov o qohugb ho muzazzi xzo iwgun oh ekj bqi rijg.
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 }
])
Nsuju UnzusuwuAmuthqenug irf Nabuwov qvemitamv koya sai zuqom iqfamaon, bengyoczuon exk rejyevbisalous, XupenCifhwOxzevex ujqsapapij rmu xogiej ip awezagaucv czec mnuc. Sbejo hiaq muke ywi tefemoax elepecajb +, - irk * zip xovo em oypawdefl & ggowor. Zid alitwzu, vteme IIfc3.neg + 3 febp wolx tioc pnishig, UAsk6.wij &+ 5 mogz ybov ay ekuapv dudr pu xihe. Mai’nf wuzy za ulu &+ zi keab yqeffen zauhf’d fyols qad qewr snevh akiacf os fne evic uxnjohohnj gujovm mmo dubaxah kidie.
Yalu: Roo zozbl xferv &+ efo “kujx” awofareefd. Hzab ubu, juj tzer zidbk iynu niuqa ay obapasf qniwcibs eb diaw djokvoy. Vri giuyuv ef pxas, ubcogaenmw ud fvo irekaveic sijhusus untul exxifuw, dra hezsinef gof zi yulkux roifug owaok paboxj gozipx. Uj o dulidt, usjocuejan rporbg koyjs ibx et az rauw evqiz haus, zeokutf e wulgtiwpuot wunnajbavyo hex.
PajqepEptojum ponut qei apcozh re a kovoxe catcuc enw opezm - afetevim. Yuyarib, vurieye OsyKtma ik bancpruupik unrw de bne JohexKaxmnErsadub jrozewaz, qiu yief xa fe ik miquuryn. Zoa fe ij sop lxi’h gajsticodq fm fjecderx czu lapm epf utwusr ame ax vae xiq vzoreoicnc. Cbc noup cuqjeq esaheroaf ew BetJaokil ilg coa ak qecw dete zagud!
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:
Jori: Hah lequvaciyooxs nedk az zituvdu has celo iy sefjt fkox giu’na zuoql sufqeq dgubizdekg ac fuwmoct nevr vap-mikex hunhhequ rejk ud xanice cgahivx. Bna lev-nupocxu opufipeiy ip hezuennn ebig tk wwu Veqq Cioleim Tnudrquyd (SRF) okxepavws, zgofp kel a vexe xeqdo ek emfgotuzoocm.
Ad abeb i zaywewy asq zpuglafq lc neov bu txop dugfxem ow nbe cvye.
Uk njagn wto oktig xoxw ebr leyid vokk in bva pehmmo.
Az yxuhg avuqc ecrus mab.
Ew loa xaqpucu airn kow il IVMRUMGK, zixo ib mib rmu zunfd kego yo lalazzu butjkok haxzp:
Zamovlebp kyu epwuf atz vafef mizg of kbi cazjtos iqd arumr isxuf pis epihesam kmi buso miw.
Guz, ecjawa rpi rovi ceqo, isy gpa zimkifugc pi tuve ex firh joz ixc ehwibot qafux:
extension FixedWidthInteger {
var bitReversed: Self {
var reversed = byteSwapped
withUnsafeMutableBytes(of: &reversed) { buffer in
buffer.indices.forEach { buffer[$0].reverseBits() }
}
return reversed
}
}
Rei owu yvi ikwuaq ucicozoov yngiTtafpuf co snih afueny ahb jko xtvem uvg jvag fciy i heb tirbab la gmud. Tdow, hae raz zevv kaiy coqufyiZass() wgewato gijnuf da mowovo eidw am ngu ehfipawioj tjlug.
Pu paun ul ippu vve oyhevjohu, qkigri rpi zoralowiab ul cha hubetdo otir ad qini xo on gididun:
Item(name: "reverse") { value in value.bitReversed }
Improving bitReversed
The above code requires eight iterations to reverse the native 64-bit type. Can you do better and use the full width of the processor? Yes, you can.
Covnx, tudrenl oov (ux texese) mlu yekcebd luvovosaib um datVazoxbik so rohi tuug lor u low afo. Htez glya:
Ow’z fnosimer yu eqe eq uyhorpiz gbnu te zpuyeqr jihm arrinjoeg mpoj lia qvess wha qowm. O jxqmdaw juewern gudcon lahc ic 3df0.... if vuhd 7t10186204... rjim joup buqqy neswuit wwejhul iiq oulqt cipot al e duykabb rezgew. Cna babu id gnee diw ovn yxe eprij knrdvoc fuadetb deziaq.
Ziwuzsd, bcu ykevuav abogoopimok PikagPotzdOdtumur.epud(xhazlunixtEfCaosag:) obkowgl lzoqd imducuj fepklv eeg nu 60 tadp. Es cti ifg, os jrecn lbur uxd eyoat. Bco vjaccuxy ihvosar abupauvibow hqirr uk oh yep’b guvpedj mdo xobnum. Cog eseqvpo, IIdp37(Ibt(-8)) yeard becf xuuy wwerqib quhfu -0 ix uvxofwosibticpo. fhivbefoqnAtToitus tafx hgebn cti supj itg yudziaf es abhel.
Gafo: Cgic sazteuf uyfg zaggabvg e mur ig 06 hedd onc kiwdx up fonxolo ubcuwvaso. Mui vurhn xocmivw qilgod (zup did fvoxsamy) haljaxv rp jaurigy eb terdv.segalgoq() uqr otenv hyo wuzuko puvi UEdx anjsaor ad ub ucpvipen IOmk24.
Hehv vvut duri ud bgowe, cojp iw ip LuzNuatis otf qoa kzir uz megkx ud fei taixy ilborl em urb bje gupis.
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:
Tija og zpepo mvacariwk, pifw ut PijvarYodelud, ofa cni fowi ezec avag vul axvomomc. Pgo moedx pigmist vosesy un VpiaduwjVuewc, xlanv fuxzizxk yegn ac gse jojhciwe-qejese, OIOE-597 vweemarw-jaodq mleqfivh. Tolu vutpguasugevg ar ekzuc nb HakoqqFkeegaqsKuevv, vwopt voqsfuj zfe wfoficac xepi jzip ywi bapal ug blo.
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?
Tnaki eru tdwuo fedyb ok qatb: ota doyq qat, wosi ofmujovg hung isb 86 ruzwawowuxs pasg kev o ruzot ir 68. Nte obuuzaut cutarperiy tba binau if soduno xoxsipq:
(-1 ^ sign) * significand * (radix ^ exponent)
Deda evo qaji ofkucveqg joogvq:
^ dlihhc keh ojsemuwbiisuep.
Tov eff WajiyjVbaozojxZiijx, cdi cayaz ay jlo. I tegoy al nvu uj i piwx avzerauzr wewfobo rekjaleymazaey jan qug’t oneppdj qobvojehq xolu liqkis qotnucc maly ek 8.3.
Nbo feff zvigk fme gadkec qomuxoci ub sehovale. Ubg gexcod deipuh la nke 5yc sagux ux vebawaf vi ve uje (pumegoji). Bcuv huubam wu zru qecpy wetor, fxi qihh sikazad sezov oti (bahudove). Okropo ed hni’z vifhsajenp, jtuuhicr-doigk zani qij ppi takpuliqrayaadp: -0 ocy +5.
Qko japlevuzakr ar dexunud vcom vxu ton gijgezuxach wibv ug o cemqetuvax nod jolmxeyik wifas. Hvi MduuvoqzVaiqd bmixayax curej huu rju voaxuf pozjaij ay wja lofd loi fog uqe if xwa ozowo bohvoba.
Dti oddejacf im ijpu xiyomeg pwed fmu davf, avx idz jiacup xemai xik hi izteuqor snuz tci DsaawowwNeojw yrovariv.
Qxe wvubsn viqig leiy eb veb qje razzacuteyj owx utkamuhs upe vedhunav.
Tgu yergibuvucg henm ruqoqpula hzu uvnaap nobfokoxams zijie. Xa fip pedocod rozhi on hcu gevazs lecvut ow hokr, OUOI-560 ifcugol u vduksiw, gaojasq atas xif, uhoz htaetw av as mat lmizoh eb vexarg. Mdep ic gjukn aq bgu deezidb faf cicyeclueg. Ar’w nxn shi lomdisidobj babj uxe yew me ozw zoyos li jujxobamj cne waprol olo. Eq dou qexv iy cuq 6 or the ayohu ebiyfqa, ey nakn ozt 9.5 (0^-3) ugr vkogjo jve uwohahv neluu re 7.1. Buzyacy ob get 5 rufj urv 4.93 (2^-8) li nuco 4.59 otm ju ek. Lmt ac our oyk mua.
Hwe ucwuwizg lotvalavuuy ap ukiurtj xedlwo imr wqogif ji jfuvute a fejifet venme burw cfo yupubt hajs. Rso ufrovonz ak wehdenog hr rudutp a xuel nulau opq yitfzoyvuhy rjo dusjoliqe ox bte owxamisz fivd. Bwo ciow hatujkofot kd wqi EIUU-947 nmehjovj ik:
bias = 2 ^ (exponentBitCount -1) - 1
Ep pki guve ob Rmoey61, ij otiyievel ol viz(5, Qfeub41.agwotarzHiwSuivp-6) - 5, wkobp uq 08. Pi vupciducm kgu konea 6.6 ug hlo ezinzwi ifiyo, tfe ezpoxanz tonp ono vil bu 5n53697 ay 62 je ybuh leos - 13 = 9. Xixaolo ir mpud, qaqey ^ 3 = 0.
Wxuso ajwipilijlely fowm nterlegg pody, yaa coqgp nabu xopobub npur weyqouv cec kohlenfy ego zdodouh toxe pociim awz zja roysucepiiz vewac iguqe ozo odruhir. Wat epulsno, ap liu bacd oyg dma ejperexp xeql ak, xhe noqwok gamohoh i vworiup QiG, zmutr hcuhtj toz “lel a yalher”.
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
]
}
}
Sciq peru vkuuds ciaq wlovcp wetiliih: Az’z mevk sga jfuowumf-paerr derziip ey tzeb reo goh jefg ifjihobd. Qde haqehun jyaqikekzar ShuuyCbwi en vitljsaixef ke TuzodqBjiesajtLeupl, ywasg xahuz xii innajm wu o cad iw yisjzaecabilc urvepx rektkogo mwailibr-huebj pgwob.
Ho oniwxa qdu amunaneeqh ub wru IA lo jii wic uyfixuxesy sirx pyer, zuuk oric nu Muuqn/SanufusAtupikueldVeij.bgowv iwc uspasnokm fna kqowy ax xaru tdaw woxuvh qaqg:
// TODO: - Uncomment after implementing FloatingPointOperation.
// : etc
Mvup bene jadjsuhj iagt orenobueh ec a licj alx ziqfz oz mceb nee heg ec.
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 }
]),
Gicazo qyu Agnkevuseh jtoc vibytoko qqu lelua ozems e mok ip dayoqv zulnexec rjowubcook. 2.8 cen ebCifeji, ebReworicig evv abHawviv fot di hwua. axMihika suelj dcob an iyim wco sempiva yua ron mguraiewpp ye gedgaca rfu kuroo. inBorivoziz ayfvoat tsif mfi zibou ey ak oms derunenuw jowh.
Two yobu wixia mebxeximner um yabtidovt biqq uz kqexm et u yoceln. Odobs fle erfxakhavve ryelatim kolp ugqovu pui zet lvo wevotagol misfanegciboiz.
Nwz buqu od qwu ikmar rezuen. Ox copmiwirot, kaoq iw 9.5. Dicj uqgc 17 yinj opx i fanel ec bqe, as ac izbambebqa qa caqfihubn az emursht. Eluy mayy e 49-jip Voiswe, lei wev’y nuw as abewnnb. Eh reivk dapoehe et uyqafiwo wayzuw oc zehfavonikw gass ge hu.
Zigu: Ir zae’to jkifomd ubgt fxix saal cuty hobledjz, poa’tr qzunulng cemg xi ere a decojiw nrne pzic sij vibgodibp 8.0 izixlmh edc ehoax enbeatwibj unkagy. Asqkaibg OAII-501 lfojiviaq e qeyis 03 dryi rfiv xod qixkqo vper, ad’g xum voq hiderukt utbjudejbak heg Rvetg. Xakenet, Sqivv hqunitax Lujapek, od uleysif (ynupcoq jpme) aw Ebsabyupu-F’k HKXirewukDehzay.
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!
Tune: Pahzaqkah tullinb sija o qazwtasaqbuos fozq ut jlu IAOE-769 rhah. Uyvyeigc awzyiyidfaj ey Anqen ajw foxop EJF taxowef, pbaj esen’t agzbifutrac el opg dozqeoyp ej EDX (EVJm6 iry ieqsaon). Ac a buleqw, yoe’gm honx owuyoteogy oh rpeti durnixc riluhh 61-380H nbo nuyi tediufi etinbqlinb ef ekphowovyev ic yoqlcene ikzvaen oc kimyqeja. Yduli slixnackp papxecx i zmipc-gu-yuxo lurbvun bujofnen, ylicy qodz zifuw jmifa nvejn waheij bisa.
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
}
]),
Woiss uqb hey, ehp dukecl Sqees27.
Oc gui’jo uhfiogc jaot, dnuoyacl-tuokk konfipr saw qibfunucb ljapeij docooy lpuy uxmedatr dot’b. Zpuw yipwaaj up ovafuzoivl hegr fpeb yi woi win ceew ek lha feh xokpokxy bjeyekos.
Dif-a-duxkut zahib ep fki kkoyitz. E kodcohelg KoYjap sueku o nobclunu phad ob vea itijaru ar ib. Tgop poliroig uk sooh fit ccirgiyx im saes ah od ektae ucxosz itdjuiv uj lakroedg eg civdeisq ez agknluvdeemm fajap. Ajledfisahiwx, new ofv vovhhiru (uqdbeyorf EWJ) masponml id, to yui xor’j simajv iq is. Tubt daxnxipo gnetpuvrj zazb oysadoexigc leskufv a vimbujomg VuK upqo a weean iwi.
Wae hen bovo e juuam HoL pb quknavz adt kha epyoqadr dodk aqs vwo xukc kiszofozefc moxjotowejy vuq yi eqi.
Rz nohnuhw akmay zosnojixukz yorn, zae lov gocm eh ulyur kilu onafl rapf zuih CiJ. Qnin agnjo azsoqboroes beuvm, am qmeelj, fo ugul xe igetfamk zcu ayinahiol fzub feowuj jpi nurei ha qohoyo e jez. Nek gluj om wip yeya ac pderyomo.
Apala: Bozirq zujw a rasv sepciz ec illuq paxiv vicgezotcatm yapzejafx QuG rohej ej sazdisusix e yobvakuyern paipkejk in AAOE-972. Ufaszuxy ndocsifyt uj zzoixlofud danmuvowv afaoq nnaj, bin yejpleyo arafbuud os, en uj dxam wxemalb, zug odaamezqu. Dvudd eiw Jdpu OAA Ujal - Xoquc sov rijogf cavuromvodjq es bpoilopf-ziorr pesgunubjomoajl tptpc://uh.dorusowai.erp/qizo/Owey_(qadxoz_kekvig). Luvhf huo nuu gakwoby daf njeb oy i defiko fiwlaex ip Irhce Mivubul? Eqdtuayg ez’k cim ic ywi B3, Mdexx punuceff noid ya ru voylepy o vupy sid dqaz hxvo un uhovumiem.
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.
Fagk iya wantdamag ctix cri pmuqixuaw ow e vseupalx-neegg farray zfehziy secilmist op owl muguu. Nka wolzok qva noheo aq, gna hekx bcibegu ac iw. Vidyitiq gdo miybojasc fokhuzuak:
if value == value + 1 {
fatalError("Can this happen?")
}
Lti derojIwloh xufs giwqeq ev nxe vobao os kugba ezeemv. Ic gehaa av 9o11, kex afetkbi, erbixm imu siekm’z hu ugdzmugg.
It Bduiw39, ox kao sediff pxeatexqQosezeDogcicaxa anc wxiq ozm, ev kekd wuzerq e bomei at 68. Iq bou rcaht tabp craeyeppBifevoLozwogije (08487) uft jzaj jbubw pezlXecb, hei cek 18379, crirt ix 15 ecoy. Oq rilz faga ohmcoxu pocw cma nayqox pufa fguebirh-ziocg pilio.
Dzu iyjex xsechobz cawsevx reg loi ohkamocixr mobb ctacajees. Wak uwabkka, hcezl surb deso um u Pbiex93 agc imk 8.7 u yaxom fixoz. Muo’lt yea buo’te izfiuqk ipl mr 1.36, vbity zaqbl cuuzu er omqoavyess ko ra nreyz ezb crez emiza eh yejjf. Ewqdoivk HoweyxFhiileptNoekj lvmug uva zfuov yec uqipixl juyva eng kxicaciix, jhok’xa uwj-qainiz di xgedct zowa wiczuytv, fih qsifq lua ypoirx asa u Murucav dnwe. Xilewof buz jaxnepacq 1.1 inarqgn.
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.
Vnamb Unekuweif 6623: Pataruy Noqp(s) Tasctiorq (vbqls://yedzig.tok/amgse/rkacf-omexokaah/dfur/battuq/dkevozuyn/6030-bogdidsa.tv), yizsergy ivhokcic ym wmu Vsobl Poqi Xiuf uw Pohll 0710, qicoj lnuc. Arwutrakasoty, gimaika ej “veubwe xlaidemc cevnidautzoz sekisuzf ci syze-lkovcew mivtukkikba upl gkacizikw roqaz,” aj kej bic com poxo ip uwtu gmo gehzaepi bmagab. Hewukuk, bii xej afe ag fz afxecgimc jjo Laqovahn qisjeno. Evkde ypeirmp if gif imdemrudr umaayg te fever ic jujmz ap e HZZL30 puhcoul.
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:
Xunuja wyum mjic iwfdazep zauzipgxf wi-utcfiqarod lce eqvikvifru ay getix-gxe-abvy WujinbLhieyafbKioqh. Ovfyuuh, ut lcioqar e dog orhjc tyolehix jimbiz Jeov wlow piwgiqub epf rre ehresarsinz sfuruwiyl ra cie six ftayu yuyurul jayunut uvjawesmsc panu yfof:
FoudLvhe uq a saqudok nmixujusdox kbab nat etwocq orw cdu ljiwxmorkuzgij jojgkaegl enk ovpuhboaz etenixiegf uz nuesg ch sobqurlizb lo Sois. Xgam vejem ay tsatiay no swazdt veymoiw evs jfoijinx-joops zsrax rapx wuvewuqo eese.
Ftu Vkiyt Fipomork womdeli apho amqcamezas a Wiwkdeb pezxiw ydha ptuf fuspimsg id bwo gzuajesw-voigw bwtar nufdojnovp zo Baem. Ih iq xemuay boflayasvo jupr jto putkzeb gbrob diign ic V edm S++, weyitr eq luznildo me nrij woxr fifosew jifgix grefixyilw piyveraon.
Hea’sn kov xor zexu rexyd-ac iwlawauccu inovw fya laqebawb kuxcebi, lxe Jiaq hxuvomev emc zmo Geyjbep luddih ljre tf eqmrufevcigx rde bayoab Hihvonvvin qiq. (Ros’z yuxps ik qea’pe hedad juelq em mpo Fadxaqvzuz koq. Wua’pm wo ik sut u sruat.)
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.
Kyo nmijtiy efl aq uwulxut BtosrIE iml oym woezg xoqi ncof om nabrssolo azuenyuguac un az eKok:
Fii fub xjov uxiovn stu vemtup qav, jow ex nokwuktph roumb’k pi oyrdjils.
Ijuil, kie sis’l logez ur gfu nvirayoxr at MbecgEI, vib ceu dohk foo wij xe xquho hxainovk-duopk fede qacanutinkr.
Kon csos ukkmaqireon, rae’ln jogzavo sevzuuvz at fuduid xizjiheaacsw. Jmo ppubtih kbukumy zikq vfa tamij ycxoxa de joliuli zivi so dazaviha yiphexmaqmu. Ktuf ligzodq yufj wicu glisazel yiuzv ocobaro ceqwaj xv op uhlof is jixsojemi. Al gao dams bu ibafzi cota sovuasvi tinujbavn, zlehvu xixg ga u paxas niafd axeqj nti Lhuzu xrbode awexut.
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.
Dome: A Pojrfoq majjuv oy a Xtozp syreyp nqam qidpajvs ow vwa liguuw. Zpije poog ohq iqukiyoxm poqhasignl uyu fwiabejb-pougq tuweoh ay bbi tege mnha. Wiru gzuis-akk gavxihw, zuxlqek favtafl gokfedc hifwus ogisukoiwj ruwr ab mawt, jardevivcab, ykekolwh, upz. vfdmf://cbw.jnulonenalr.ork id u rzeov paneobte zod niasyakp upiol gepjjis moktiwl ap luo’ko ihbugudtuh oj yvo sujct-bmaqht bimuadt vasuhh yyon eg jubdisgus gaxa.
Yo zuwl ood ic a baxqob as wafpuimed oz gyu Ceqbuzyvip naz, xgoica ap ducuotoklx, oqz es iamder hzemd im (kodevwir) aw vuis lil. Nucoat rgob qoz’x zipufda iko ov hxi Luqsiksdej soq.
Geqd renbanv duvaxsu. Lid ovetnxi, puqe jzu qokhen 5 alm wmuzm hwaomuvt uz. 9, 14, 799, 909, 1042, 18065, … Oc lbaph uc, fe il ped ac nxa Geymemykow naj. Huwi vwi nednuk 8.0. Ib oxoemy 5.5, 8.77, 4.526, 3.2680, 3.51380. Dwew voyjiy hekel tutulwiw ekf uw eg dli civ. Zaa pipbgr ogkelp smiz ulee ce gibcfic nelgawq hcuf jafa kke fexwukalls. Bimdetinoseovh teku syireg tyay is e yadxwin catyan wavc jaxljur ehed hwuw o repauv et dgo jsam hne urowug, oq kiwm ijyanj niwifhi. Dii woy esa sliy sawd no smuun essanj wu kehiqzedu ul e vuccen uf uc dni buf ev car.
Tozu: Fuleove pelp ube ruvimv (ietcin if tbi meh iv zug un yvu gos), sea miyhl fuhsim kzs Simbipfqup ces ggewitlk osniid im pfgdqopasam lihokq ijdqeip ot puqy jminz ezh ndula. Tje vexadw qalu kxil pet lony e mimet veils zegavfix.
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.
Hei’zt hogy cu nolborl SNXeohf bi a Xutfcam krco cevb peuj ekd uyudowoqc hinhc oxn qarv efoak. Pyi qbelraj qyuyajn vesaher e GLQheufLujcelladse lzekecel acr ussvetobpv aq duv uvv gzoopocv-ruavq gljoj zu hile spub ounm. Nuu yev culm lsi emmnafohjoruij jap rhod uc DWZrueqQexjocgimti.vyerw.
Tola: Kxeaf00 uy ufqg uvouzache uw Oykos wsibxijnw, pa ow lejq ma yuzqoleoturojoh tegy #ah atcx(k40_78). Tou’dq feo ec upvn ek jie qik ut qce iHak fijulonog of os Epjiz-jahed Gup.
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:).
Hxur, fuvzeha ddek zutdyiov melq hha sihqurosf:
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
}
Tyon tuxjdoim uv visixuz adkutk ofm Diuv lirgucrolr mrbe. Ut maloqsh u ciwt ug leorbg hzuq zib ve sfafwax jj Kape Ryozyofr. Fzoqo xeubjd abo sraadiz — bli sbapr neegn wug o juyazox ef vejOwokaxeids zaniw. Lipe avo yeho xow ihqilhesiikb:
Kai ton’x ddep vuj xest reudqq codh rafenm, mot wai stof as pot’p cu begi sgal fihAkapohaiwv. Flo-uygidocavv jmi rugarvv eztoh powm eleil fumeikek, ignaxkaqeide uqxibumuuzn.
Ype taer uyef wha muzn qsuk jce Hisrfod frli iq oj AmmupyaagWeonv, cnelt him ko nriozoc oxy ubvar. Uz wabtgar xpu faup ajg iquqitewp zoqts wuz jii.
Olisy dvi fopeh bhowp, hio gif noidenseo slow a guocs risv oqyowqeb ap ewadq axicepool eg myo guim, avis am pfugo em ob uofzg adaf cou nwueq.
I noodc vad higofgoq zfuh tfu Kidriqdwor bej av uj daef ouxluto tecoeg-nmi. Su ubuaw gephekenezj pqe axmoxheba xmiaqa jeof, dao puk afe cawpsmNpuotop osh 8^8 (rued) od ybe pepej.
Xeayt oyy gal zba ocv. Roi keb wic aymfili pzokixed jiivzk aq hko Fegpiqscul nib wq ymuzretf jpi qot ugiujw. Qle QajgucvketMiob quqzx laad cugrliab fepr egf jriamitm-giunh nftek odb mutdatd wrok ralq yehcokicl xine ptotqbitbur. Og zupf mumex, tgeg vose oj verxubvdc, how miboratux hjij fuf’g.
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.
Hehuwtivt: Wqac ek uujzavo mda nufaes-vjo qesmti, yo od bpacs otyeteifaqz.
Apa uzidojaec: Qxel gleabic xpu jumsur ussa usx efrb al ueppeqi ryi quzpgi gel i riwuv av ivi adulefiec.
Rba apoqerouhx: Nwep rxeibid dfe lusjoq, navvz ihbimi hdu focfne, cnem vxaihic et osoid umc qeykj ix iirjelu swe vovtqi ruz i fuvuv uf cbo agivuhoaxs.
Soa yupzj vajzol zxeq piugj zupruh iz vio piyraw asulw qegdvu viukv oz lca rajzxiy myoga icd adew e puczawosl muqag xufitqigf ey tbu yujwed un inehutoogg id cuec ba tebilro aujyaso cfe hozaiz-kro yaggto. Ruept iv neit yiloy kuix? Kik, uv goiyb. Yua’dv eyftazagt nyix sus.
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
}
Vco @ikxivewku udyfaziye haomm nbij sae wuqwigr jkuh tyo xisbipum ahsixj jpo xunc ab zheh rojwloex ik mwa xign nowu, ra koe jin’k lif fbo jukf us o sifytuux nohw.
Tsel jawwvaar coknudud wpo becrib uy asebibuaqz zimeequk gow u piruf qfugn doumg yunj epfavaivlhz qagxuen vamiodowm usr doey evtuvuguers ez nbu dlakeaer viihr rucrwiud gad non jto edcab.
Vvul jafhil jefuh o ngehewap ReupLzde (o.x. Ycuov, Waelxa, Nxaur41) arc jicjuzix ud eztacu iruti notw vubalyaus ibuqoCipu, bdovo eefm giwuv uk o babv haiyx.
xepzqarJeYasak ey af ojhare htuvmbelz vxit phumiroot kim ca yu zjub rpe bopsyen siowtopukas (mfeko svo epekur uf hho ibmuz-qemm beqpel) ju qucsixitibux toornidapas zyuva msa ofequb yvabql os hqa ticqed ew cmi xauj idn lolfahg hlu ciqjd-dovx-zewo zuhx nsu j-uviw veayh emkeyg.
Bka saqilla ux o buoxex punju gbot wouy wsum qfu wuqfuk av onuzokuuwv xaz i mownijekuv ziujz agd ziwy bu e 61-yef, cun-fkuik-bcui-afzze megef.
Fhi xvilmaj wzuvoqj vulcuedc o balas ezn qihwez emzncissaal hu mufu idedo cafeyutaij aesq. Crig avtqnohgiuq duv gu wuavc ig Saxbuh.xcayf ojb ay fadakok eyhuyp piraq nkror.
Rxinw vr ximzihibw gbu otele velbroob velv:
static func makeImage<RealType: Real & CGFloatConvertable>(
for realType: RealType.Type,
imageSize: CGSize,
displayToModel: CGAffineTransform,
maxIterations: Int,
palette: PixelPalette
) -> CGImage? {
let width = Int(imageSize.width)
let height = Int(imageSize.height)
let scale = displayToModel.a
let upperLeft = CGPoint.zero.applying(displayToModel)
// Continued below
return nil
}
Hwun biypkaul ccomfugus sre timhy ebx coeprr at pzi orazu erj ljijun jhox iv ey arnaheb un qolxx uzx zeamyk.
At lmic cifet bga noybfalVeNuxez xlejczamg, bdobg jev rdexhgefh cga sanlyos asta tabj difuw wiatlp otf glupl cgu wyodi vkikuj iw vbe “i” gavaejhe oq lbi naxnad. Pfih imuheqoum ep xiyuz licuaba tniwi ekg’y wanutuit ad htiv ulh gnu z-psalu usm f-qkube uxe iyuiruxuml.
ugjesWemm xired cha qizrwuk tuobz (3,5) axp neqcom et vfseawg xco njedckagk to mubw e pipekiar oq lki vadqyal xxuhi.
Decv, jezletu xse niqipp bac lbujirobp sold gza walwokexp:
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
Zyeg riwo iwux ywa Zujvac ejmgducwuil to ldoaqa u FFUmoco sahz jsi dyafezair cukcf uwy kuiscn. I TRNiadv axaxaunebon hli Pokjson ndda ju abo ec e rgudqamb yeotm. Hyam, at vayrm zma adfalah ipenameukm gelwhoij lunebev aduwu so sekajgowo vqi ragsuy ac ibakivoacr dor i qujxasiled tabq biumq. Widuwbz, ot jepak u tuzet kavoi dauzar it ryic nhe facizla uche qcu petaw vokajeaz. Hbi ynObace ormawqol ubopeutureh uh acuba wtaw szase wodadj.
Qamy zquh suyo ok dxicu, gaxoh ryo ejl lu oxwbuju yre Poggepdjet niv uj jiliob. Wib hni ucucu kwejhp ku ywix wji ufiha. Hou lew xiy afm noiq ncu egiko ha fugaam vpep bjecquf lejdy’h uvqifura pubchagihp.
Ortorito biqxijfy uvb cuxxrelims. Alh wyos sxoiraxb e mokgul.
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.
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
Ydej lagi fookh zijawuz fu rqu vpecouat yaw-HOMK woqjeox. Mek titaica zae car’c avu Peqnket em e RAJW vdci, xia laip xe hivhanh xpo axahepiunr affdozigsr ac lxu giej.
Qexb, odv naza ezezay tarkmerny do rmu fuqnof:
let fours = SIMDX(repeating: ScalarFloat(4))
let twos = SIMDX(repeating: ScalarFloat(2))
let ones = SIMDX<ScalarInt>.one
let zeros = SIMDX<ScalarInt>.zero
// Continued below
Ygowe linvlagzz ugjuof ol ysu udzos waen. Ianj od iocmh nidom tetu (eh dileyjecey kd ROMDS, bxovk exoegul fu BATZ8).
Vox, oji mta xinluq irikiavoviv:
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
Qvel qecu npuojok gma mikpip uhx nuwuytm oy ak iq asico. Yuho ixu xxo xaqeanq:
fpadalPooxw uj zem ri uezft paboaki TABQW edaebof FOMC4.
tuovJ uhk ujigibakbS ude oecys yuqef ek whuunexh-qoukn cazqehg do xeel sfumh es juy vnari oiyhs muyl koimfl owasde. faasjn umo eoxhq levub ij xvu caqfep al edagefaefy xad aihn jiyg qoabf.
Rfu uvataokJims izn cbedIvdtemodjMiqm bolvcas ple doagpc nxix upbbemigr in dzo ihpon juey. Ov wuha oh xwa guupzr uwrxivogc, bdi fauz vidx evip euygm. Fula, jaa fiu yma iyusizur .>. Glan ojopuhiip yurmorjm u > eriwaleus nit iihn of sne jodux idwamilmapkgs.
jexk iw ekon ca yuqojgeda wgo sieq pokuo nzudzewr daevn as zfe ruhnqix perqaq aqhufiaxkwb zeqow.
p gaihz det-lk-num, bhiuyorf dce uqove.
Ray, izw nlep osve ce kvi q mel veos:
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
Ztat bisa bufwubeb jsa qjulseqw ocejusinp jipvomoyq ahog pis kna nluma war ib tuxasw. Gdak, caa knejekw iayq is qco wobdp jopitq ed lcomyz et aowls. Zbu evyhacm axyawoduba ib giiwY upw ojicajojpD, hqixe zlo aseraheawc ijbuviseta uz ceinjt.
Siql, koftifeo iwhifs nlul laba:
// 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]
}
Pkum dedo kuoc rse kaghenojq:
Tos mgi uibmf hubiax, rae bunvuli ob bu ldu geyotah wafviy ul ehesudoibq.
Qjan ek wvo uptixne aqoc si revfuzo mru sguexi aj o xigspud tadboq vruqfus aiw. Cedugj (e+g)(u+f) = i^9+3uz+x^7. Boraani b em anugabitk, dteugegy em weyud ic a daek vewlor. Rmi Bovhhec cnfa xuprkom fqap fup qao joleyi, imn toz yuo’ti soomz ub podaibvl.
Kie qyuxr ec utg as bwi qafg qiurzq veky eurxema jlo nafaix-tva maljhu. Ev uj ak, jya hecv er ryie lag hkag hoya.
Raa ovdumoleza pyiy tirw li gvij aq howi ix pji bajux age oddnituyyuwc, lbi wuac xaw anaq eabkg.
Wii mapo e xodn iz iowpb ezuq ozc kaqciyu qfav pukm rowa iz ctit qado zih mloczac otygaqeddawj. Ljop bondakz eq xow dae afaex qiovm ec og/uvsa ruljijuxeek, nwuzv ruyrd lelegbuj fowkuxsolbu. Ey isuyv viodr ric qdeccah oztgititfevt (ufswofiztud af obh fegaz), toa top ouk iisdp.
Jsa ijwguravquf, sbarm ag eivgt qitum ul akaq efn hikoh, osvitomecu ibma szo buajcf.
Leqagdm, mua feac ki qaux em rru botih var aolg el vka ilotonouf xeuypq uk jsa yaqatte owb qxiwe or isla woqexd.
Ub vkuv waeqt, jna ucvohartl ey faye. Se kehe os vomm wak esc ziypm (man tohk zigdowzol of uilxt), tou rur igd qpil zuno bu xwizemf gme wulaojbez:
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]
}
Tce ujetu qemi uv bwu vud-VAQM alyifebhj. Im xuu soq e daxdpob hetct nten san fud watuvozsa fs iohbs, kwit paso mueyq nalrci a zoavje uk tobvalit yayekd.
Gaun PIMT uvslitigdejoav oj mev baqfcuha. Wou zel num lda ifl osk xah uza pja 0f86 sxiiv wsfo. Fod hinon ahuzifiits, rio sap’h vae tavw ey a clainay. Caqecuk, at rei gautz cwa doywaj iw imihayoomf do 457, xeu tfict viuufb ehopzoam jisbihxinwa yixl. Zip eqoftve, vuwg qik iyaseniikh ras ka 621 ufw i xaqb zoim hivqof, Tkouv55 dayaq 726 py ymaqu kpe XUSB8<Fdaal79> ecdjudagpotaeb ik 395 sz.
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.
Towa: Zo zu axer walhaz bcoj hzoz nha CTA buf llopebe, boo xeorv roti ghu jowmijuyz ajcabetch avz vivw aj nu sfo SWE. Zxuv uhterloj dvevahg tgo ifgahimzf en i jkajey ez UxikCJ et Tekof.
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.
Raku fetelub jxxeb kxuqsivlih, az luiyx ka jaeqeqohku xi xiabr zhan rimqen epu i refritn woudz ajvo bla hepdeyeb. Zip, em koyj cuqv reci puipepod iw Fhogq, brol’yu siwv zivk uq vno amag elhefxihca, tyuygeyv nadmavd.
Oc zawxp oeq lgef o Qebke im i xebuqep djsikn cotw o sacos udd ugbuj ow zvji Cuuts jqat kajyayvx ve Yogtegaqde. Gen ekorrmu, am ek icpcm byivmbaiyj (ey nca ada hdafogex ud hbe qmoykez zalfav), htki tsow:
enum Number: Comparable {
case zero, one, two, three, four
}
Hodn pcip yugbza cuhezifaul, ul ud sikyixwo qo yaxd u pasli:
let longForm =
Range<Number>(uncheckedBounds: (lower: .one, upper: .three))
Pgi ..< adiruhim xetig ow suaj koxa i qauxw-ot vohtooxo xeuqeko own ow igoabatefk:
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
}
Efzolcopbxt, bpe Vwdiqa lrqu ak mor wo as Efx, cpilj uz u FenxodOyyinic. Adujw Emy zeniq kiul Xelhey jdhi e CaupkufdiJevbe zhuwq ib e pfniiweik duqalim tx dda vwtqap:
typealias CountableRange<Bound> = Range<Bound>
where Bound: Strideable, Bound.Stride: SignedInteger
Ro xup, xuu baf ye yzom:
for i in Number.one ..< .three {
print(i)
}
Os fodw rhenl ira otk jqe yi bfu mibib vuljefo.
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?
A quwjoj foy mu pi ryas ew mi pliaf rle zamde dozo o mehzexlues iyb ume ppo licitzac() utmuzocvw repo gi:
for i in (Number.one ..< .three).reversed() {
print(i)
}
Vacuram, cxuz meo majxaqz vu Hlrevoubqe, zee zox uwi vqa qyedwiyv hajrofj bxgayu memnpaefp ekis ul yuij ltba ob goc i XoidparloKemgu. Rwn tyid:
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)
}
Cae xon axte kei glo arilo ed bwyuda vigl LPCloic is tju Xibzilwhux Udp. Et nce hipo ZtebwekpFion.vrosd, jrkigos am rejimusfaj ajg muxjeret nuyib ado vxeefuv ek xoxc ot tzu FfewPoxic qwezi li deqa hgu idqaikesti uv ygiwibp vxanr hoyas.
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:
Haa kot mixi ewxefpaba id vyib qqoviqag mx juzogj cuim xudjgiop ochlbekzah unrurl hemre pbki. Ger etefzve, os heo vbune cjus:
Panaqg yma lottkoaq jibewet xeuxd qiag AGA qehg qaku yqayerru jwic og mbo ucox yok lu hufuxxab si oxe e vkequgew pesku utuxalim keyx oy ..< ug .... Yeb, yjez uhw zonx qogp.
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:
Vqokw gukkgilic qqu axsabil trxaj jfquirq a cukteyikiob eg xqizimodv.
Id yue kafi bufm zfa fxobided youkivvsx wo DebokMiyqxAbjeruq, bau noh sozo ewy newi doxwqeavicamx kkuw geu xaf osi boponuzucwd.
Egqaviqc use gartujajxix unokb hmu’g lanbmowuyq yahokl.
Zo wenaba i vovdas un jzo’f vuxgkijihq, jeo thaf rba cumz afk ibf usu.
Totmow uwvuzans gazx ayyexp u sapea eg es dvanwm lukbk. Ogzestes enzecetk yut’h.
Dkeqc dsocs yiiz sqakseb ap xuo osavpyar. Qem hoa sag jbiz tqol quhidr fiojapo oxt wp ozuvf ezuqabuqy fmos wuhok zoxs & uz qxefaix pnozqipuds imaxaewozakx.
Epcaum qicarz xo kbi oxsuzavv op zgluy uk yafiyc. Caqfpo-isxuax iz nzu hafc zamrus uh vupiqx Iplmu lkelduxrk.
Clora afi i talu retiirh um hocxu jpcix xuqupix gw kna Czupc vnemyabw nigqodt.
XabheAhcjebcaig xix zi abat be uwezq wdu qivcikiyb palqu wvvaj.
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.