ทับทิม 2.4 รวม Fixnum &Bignum ให้อยู่ในคลาสเดียวกัน (Integer ) ดังนั้นฉันคิดว่านี่เป็นเวลาที่ดีที่จะทบทวนประเภทตัวเลขต่างๆ ใน Ruby!
นั่นคือสิ่งที่เราจะพูดถึงในโพสต์นี้ 🙂
ภาพรวมของประเภทตัวเลข
เริ่มต้นด้วยการดูลำดับชั้นของคลาสที่เกี่ยวข้องกับจำนวนทั้งหมดใน Ruby:
Numeric
Integer
Fixnum
Bignum
Float
Complex
Rational
BigDecimal (Standard Library)
อย่างที่คุณเห็น Numeric คลาสเป็นพาเรนต์สำหรับคลาสตัวเลขทั้งหมด จำไว้ว่าคุณสามารถใช้ ancestors วิธีค้นหาคลาสพาเรนต์สำหรับคลาสใดก็ได้
ตัวอย่าง :
Fixnum.ancestors - Fixnum.included_modules [Fixnum, Integer, Numeric, Object, BasicObject]
ทีนี้มาดูคลาสเหล่านี้ในรูปแบบตาราง:
| คลาส | คำอธิบาย | ตัวอย่าง |
|---|---|---|
| จำนวนเต็ม | คลาสหลักของ Fixnum &Bignum | 1 |
| แก้ไข | ตัวเลขทั้งหมดที่พอดีกับประเภทจำนวนเต็มของระบบปฏิบัติการ (32 หรือ 64 บิต) | 1 |
| บิ๊กนัม | ใช้สำหรับตัวเลขที่มากกว่า | 111111111111 |
| ลอย | เลขทศนิยมไม่ชัดเจน | 5.0 |
| ซับซ้อน | ใช้สำหรับวิชาคณิตศาสตร์ที่มีจำนวนจินตภาพ | (1+0i) |
| มีเหตุผล | ใช้แทนเศษส่วน | (2/3) |
| BigDecimal | เลขทศนิยมที่แม่นยำสมบูรณ์แบบ | 3.0 |
Float Imprecision
Float คลาสใน Ruby ถูกอธิบายว่า "ไม่ชัดเจน" ในเอกสาร Ruby อย่างเป็นทางการ
ทำไมถึงเป็นเช่นนั้น?
ให้ฉันแสดงตัวอย่างให้คุณดู :
0.2 + 0.1 == 0.3 # false
เหตุใดจึงเป็นเท็จ
มาดูผลลัพธ์ของ 0.2 + 0.1 :
0.30000000000000004
อย่างแน่นอน! นั่นคือสิ่งที่เราหมายถึงความไม่แม่นยำ
สิ่งนี้เกิดขึ้นเนื่องจากวิธีการเก็บทุ่น หากคุณต้องการตัวเลขทศนิยมที่ถูกต้องเสมอ คุณสามารถใช้ BigDecimal ชั้นเรียน
ลอยเทียบกับ BigDecimal
BigDecimal คือคลาสที่ให้ตัวเลขทศนิยมที่แม่นยำตามอำเภอใจ
ตัวอย่าง :
require 'bigdecimal'
BigDecimal("0.2") + BigDecimal("0.1") == 0.3
# true
ทำไมเราไม่ใช้ BigDecimal แล้ว? เพราะมันช้ากว่ามาก!
นี่คือเกณฑ์มาตรฐาน :
Calculating -------------------------------------
bigdecimal 21.559k i/100ms
float 79.336k i/100ms
-------------------------------------------------
bigdecimal 311.721k (± 7.4%) i/s - 1.552M
float 3.817M (±11.7%) i/s - 18.803M
Comparison:
float: 3817207.2 i/s
bigdecimal: 311721.2 i/s - 12.25x slower
BigDecimal ช้ากว่า Float . ถึง 12 เท่า และนั่นเป็นสาเหตุที่ไม่ใช่ค่าเริ่มต้น 🙂
Fixnum กับ Bignum
ในส่วนนี้ ฉันต้องการสำรวจความแตกต่างระหว่าง Fixnum และ Bignum ก่อน Ruby 2.4.
มาเริ่มด้วยโค้ดกันเลย :
1.class # Fixnum 100000000000.class # Bignum
Ruby สร้างคลาสที่ถูกต้องสำหรับเรา และจะโปรโมต Fixnum . โดยอัตโนมัติ เป็น Bignum เมื่อจำเป็น
หมายเหตุ :คุณอาจต้องการตัวเลขที่มากกว่านี้เพื่อรับ
Bignumวัตถุถ้าคุณมีล่าม Ruby 64 บิต
ทำไมเราถึงต้องการชั้นเรียนที่แตกต่างกัน? คำตอบคือในการทำงานกับตัวเลขที่มากขึ้น คุณต้องมีการใช้งานที่แตกต่างออกไป และการทำงานกับตัวเลขจำนวนมากนั้นช้ากว่า ดังนั้นเราจึงจบลงด้วยสถานการณ์ที่คล้ายคลึงกันกับ Float vs BigDecimal .
คุณสมบัติพิเศษของ Fixnums
Fixnum คลาสยังมีคุณสมบัติพิเศษบางอย่าง ตัวอย่างเช่น รหัสวัตถุคำนวณโดยใช้สูตร
1.object_id # 3 20.object_id # 41
สูตรคือ:(number * 2) + 1 .
แต่มีมากกว่านี้ เมื่อคุณใช้ Fixnum ไม่มีการสร้างวัตถุเลย ไม่มีข้อมูลที่จะเก็บไว้ใน Fixnum เนื่องจากค่าที่ได้มาจากรหัสวัตถุเอง
นี่เป็นเพียงรายละเอียดการใช้งาน แต่ฉันคิดว่ามันน่าสนใจที่จะรู้ 🙂
MRI (Ruby Interpreter ของ Matz) ใช้มาโครสองตัวนี้เพื่อแปลงระหว่างค่าและรหัสวัตถุ:
INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG)) FIX2LONG(x) ((long)RSHIFT((SIGNED_VALUE)(x),1))
สิ่งที่เกิดขึ้นที่นี่เรียกว่า "การขยับบิต" ซึ่งจะย้ายบิตทั้งหมดไปทางซ้ายหรือขวา
การเลื่อนตำแหน่งไปทางซ้ายหนึ่งตำแหน่งจะเท่ากับการคูณด้วย 2 &นั่นคือสาเหตุที่สูตรคือ (number * 2) + 1 . +1 มาจาก FIXNUM_FLAG .
ในทางตรงกันข้าม Bignum ทำงานเหมือนคลาสปกติ &ใช้รหัสอ็อบเจ็กต์ปกติ:
111111111111111.object_id # 23885808
ทั้งหมดนี้หมายความว่า Fixnum ออบเจ็กต์จะเข้าใกล้สัญลักษณ์มากขึ้นในแง่ของวิธีการทำงานในระดับล่าม ขณะที่ Bignum วัตถุอยู่ใกล้กับสตริงมากขึ้น
จำนวนเต็มใน 2.4
เนื่องจาก Ruby 2.4 Fixnum &Bignum เลิกใช้แล้ว แต่เบื้องหลังก็ยังคงทำงานเหมือนเดิม
Ruby เปลี่ยนจากประเภทหนึ่งไปอีกประเภทหนึ่งโดยอัตโนมัติ
โดยไม่ต้องเปลี่ยนคลาส .
ซึ่งหมายความว่า Integer . ขนาดเล็ก ตัวเลขยังคงทำงานในลักษณะเดียวกับ Fixnum .
สรุป
ในโพสต์นี้ คุณได้เรียนรู้เกี่ยวกับคลาสที่เกี่ยวข้องกับตัวเลขต่างๆ ที่มีอยู่ใน Ruby
คุณได้เรียนรู้ว่าทศนิยมไม่แม่นยำ &คุณสามารถใช้ BigDecimal ถ้าความแม่นยำสำคัญกว่าประสิทธิภาพมาก คุณยังได้เรียนรู้ว่า Fixnum วัตถุมีความพิเศษในระดับล่าม แต่ Bignum เป็นเพียงวัตถุธรรมดาๆ
หากคุณพบว่าโพสต์นี้น่าสนใจ อย่าลืมสมัครรับจดหมายข่าวในแบบฟอร์มด้านล่าง 🙂