ทับทิม 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
เป็นเพียงวัตถุธรรมดาๆ
หากคุณพบว่าโพสต์นี้น่าสนใจ อย่าลืมสมัครรับจดหมายข่าวในแบบฟอร์มด้านล่าง 🙂