Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

วิธีการทำงานของตัวเลขในทับทิม:การทำความเข้าใจจำนวนเต็ม ทศนิยม และทศนิยมใหญ่

ทับทิม 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 เป็นเพียงวัตถุธรรมดาๆ

หากคุณพบว่าโพสต์นี้น่าสนใจ อย่าลืมสมัครรับจดหมายข่าวในแบบฟอร์มด้านล่าง 🙂