天天看點

《Core Data應用開發實踐指南》一2.6 單精度浮點數與雙精度浮點數

本節書摘來自華章出版社《core data應用開發實踐指南》一書中的第2章,第2.6節,作者 (美)tim roadley,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視

對于屬性來說,單精度浮點數(float)和雙精度浮點數(double)這兩種資料類型可以看作帶小數點的非整數。它們都可以用來表示實數,但也都有一定的限制。單精度浮點數與雙精度浮點數都使用以2為底的數制(也叫二進制),對cpu來說,這是一種原生的數制,它容易引起舍入誤差。以1/5這個分數為例,如果采用十進制,那我們可以精确地将其寫為0.2,但如果改用二進制,則隻能表示出它的近似值。小數點後面的數位越多,精度就越高,表示出來的近似值也就越準确。高精度的數會占用更多記憶體,以保持其準确性。

與單精度浮點數相比,雙精度浮點數所包含的二進制位(bit)的個數是它的兩倍。單精度浮點數用32個二進制位來儲存其資料,而雙精度浮點數則占用64個二進制位。兩者都采用科學計數法,也就是說,整個浮點數是由尾數和指數(表示2的多少次幂)組成的。雙精度浮點數有64個二進制位,這意味着它的取值範圍比單精度浮點數廣,精度也比單精度浮點數高。

在ios中,最大的單精度浮點數是340 282 346 638 528 859 811 704 183 484 516 925 440.000 000。單精度浮點數與雙精度浮點數都有符号位(sign bit),是以,ios中數值最小的單精度浮點數是340 282 346 638 528 859 811 704 183 484 516 925 440.000 000,而數值最大的雙精度浮點數則比數值最大的單精度浮點數還要大出許多。本章最後有道習題,題中給出了一段代碼,可以列印出各種數值資料類型的最小值與最大值。

在單精度浮點數和雙精度浮點數之間取舍時,需要考慮正在配置的這個屬性有何特點:它的最小取值和最大取值是多少?是不是真的需要超過7位的精度(單精度浮點數所提供的精度大約是7位)?如果不需要的話,那麼在ios平台上還是應該選用單精度浮點數,因為在64位的iphone 5s出品之前,單精度浮點數這種資料類型更能夠同底層的處理器相比對。雖說使用一大批雙精度浮點數特性看上去有些不太合理,但是要注意:資料庫可能會導緻程式在存儲量方面的需求變得比想象中更大,因為它們可能要包含巨量的資料行。目前裝置的能力和容量都很大,是以在大多數情況下,使用雙精度浮點數其實也可以。如果追求浮點運算的速度,同時又不太關心精度,那麼選用單精度浮點類型會更加合适。但在涉及“元”或“分”等貨币機關的财務計算中,則不應該使用單精度浮點數或雙精度浮點數,因為“舍入誤差”會導緻錢數出錯!

根據實體來建立nsmanagedobject子類時,如果實體中某個屬性的類型為單精度浮點類型或雙精度浮點類型,那麼在建立好的子類裡,相關特性的類型就會是nsnumber。

在涉及貨币或其他十進制運算的場合中,建議把屬性的資料類型設為小數(decimal)。與二進制不同,對于cpu來說,十進制并不是原生的數制,這就意味着以小數來運算時,處理器會有比較大的開銷。與單精度浮點數和雙精度浮點數一樣,小數也是由尾數(該尾數是個整數)、指數及符号組成的。雖說記憶體占用量和處理時間都比較多,但是小數的計算精度卻很高。在這種數制裡,0.1這個數就可以精确地表示出來了。如果屬性的資料類型是小數,那麼它就會把0.1存儲為“1/10^1”。

與值最大的雙精度浮點數值相比,值最大的小數其實并不算大,但它的精度卻比雙精度浮點數高出許多,而且在有些時候甚至是完全準确的。本章最後有道習題,題中給出的那段代碼會以1/3這個數為例,列印出每一種“數值資料類型”所能達到的精度。

根據實體來建立nsmanagedobject子類時,如果實體中某個屬性的類型是小數類型,那麼在建立好的子類裡,相關特性的類型就會是nsdecimalnumber。在nsdecimal-number上面執行計算時要注意:若想保留精度,則隻能使用nsdecimalnumber内置的方法。

對于屬性來說,字元串這種資料類型可以存放字元數組(array of character)或普通文本(plain old text)。作為objective-c程式員,你應該已經對字元串相當熟悉了。根據實體來建立nsmanagedobject子類時,如果實體中某個屬性的資料類型是字元串,那麼在建立好的子類裡,相關特性的類型就會是nsstring。

對于屬性來說,boolean這種資料類型可用來存放“是”或“否”這兩種值。根據實體來建立nsmanagedobject子類時,如果實體中某個屬性的資料類型是boolean,那麼在建立好的子類中,相關特性的類型就是nsnumber。若想從nsnumber中擷取boolean值,隻需向該執行個體發送boolvalue消息即可。而若想将nsnumber設定為某個boolean值,則可使用numberwithbool方法。

顧名思義,日期(date)這種資料類型就是用來在屬性中儲存日期和時間的。根據實體來建立nsmanagedobject子類時,如果實體中某個屬性的類型是日期類型,那麼在建立好的子類中,相關特性的類型就是nsdate。

如果要儲存照片、音頻或其他由“0”、“1”二進制位所組成的連續blob,那麼就應該把屬性的類型設為二進制資料類型(binary data)。根據實體來建立nsmanaged-object子類時,如果某個屬性的類型是二進制資料,那麼在建立好的子類中,相關特性的類型就是nsdata。至于如何在資料和nsdata之間轉換,那要依照具體存儲的資料來定。二進制資料較常見的用途就是存儲照片。存儲照片時,可以通過uiimagepngrepresentation()或uiimagejpegrepresentation()來把uiimage轉換成nsdata。而擷取照片時,則可以通過uiimage的類方法imagewith-data把nsdata轉換為uiimage。二進制資料這種資料類型對于大檔案來說比較合适,因為在屬性的設定選項中,我們可以開啟allows external storage,将其“無縫地”存儲在資料庫之外。啟用了這個選項之後,core data就會自行判斷是把檔案存放在資料庫内的效率高還是存放到資料庫外的效率高。

可變(transformable)資料類型很适合用來把objective-c對象存放到屬性裡。這種屬性類型比較靈活,它可以存放任意類的執行個體。比方說,uicolor類的執行個體就可以儲存在類型為可變類型的屬性裡。在根據實體來建立nsmanagedobject子類時,如果實體中某個屬性的類型是可變類型,那麼在建立好的子類中,相關特性的類型就是id。若想把id對象放入存儲區(或将其從存儲區裡取出來),則需借助nsvaluetransformer類的執行個體或nsvaluetransformer子類的執行個體。nsvaluetransformer類可以在屬性與nsdata之間“透明地”執行轉換。轉換過程也比較簡單,尤其當待存儲的類本身已經實作了nscoding協定時更是如此。假如實作了該協定,那麼系統就會提供預設的transformer,而這個transformer自己知道如何“壓縮”(archive)或“解壓縮”(un-archive)相關的對象。

請按下列步驟修改grocery dude,以便配置其中的屬性:

将name 屬性的type設為string。

将quantity 屬性的type設為float。

在item實體中添加名為photodata的屬性,并将其type設為binary data。這個屬性用來存放貨品照片的圖像資訊。(注意:目前并不啟用allows external storage,本書後面再講解何時啟用它。)

在item實體中添加名為listed的屬性,并将其type設為boolean。這個屬性用來表示貨品是否已出現在購物清單中。

在item實體中添加名為collected的屬性,并将其type設為boolean。如果使用者已經拿到了所要購買的貨品,那麼這個屬性就是“真”,這表示該貨品已經可以從購物清單中勾掉了。

執行完上述步驟之後的資料模型如圖2-4所示,現在每個屬性的資料類型都已經配置好了。

《Core Data應用開發實踐指南》一2.6 單精度浮點數與雙精度浮點數

為了給以後更加複雜的資料模型做準備,筆者在這裡告訴你如何切換到圖形化的編輯界面。要改變編輯器的顯示模式,隻需點選圖2-5正下方的editor style按鈕。圖2-5左側示範了編輯器在graph風格下的樣貌。

《Core Data應用開發實踐指南》一2.6 單精度浮點數與雙精度浮點數