หากมีคำถาม ขอให้ไปโพสต์ลง เว็บบอร์ดจีทูจีเน็ตดอตคอม ตัวใหม่แทนน่ะครับ

หรือติดต่อเข้ามาทาง Inbox ที่ เฟซบุ๊ค ผมครับ

หน้าหลัก
ข่าวสาร - บทความ ทั้งหมด
VB 6/VB.Net
ASP/ASP.Net
จับฉ่ายคอมพิวเตอร์
เรียนรู้ผ่าน Flash Movie
บทความที่มีผู้ตอบล่าสุด  
 RSS Feeds
 ดาวน์โหลดโปรแกรม RSS Reader ได้ที่นี่ ...   Download โปรแกรม RSS Reader

Forum - www.g2gnet.com
Webmaster - www.g2gnet.com
Visitors - Session views
 5 5 9 1 6 9 0

7 ธันวาคม พ.ศ.2549
39 Users On-Line.
Visitors - Page views
 8 9 4 6 7 4 0
1 กุมภาพันธ์ พ.ศ.2551

Google   
เว็บ g2gnet.com
ขนาดตัวอักษร:  

แจกฟรีโค้ดฟังค์ชั่นในการปัดเศษเลขทศนิยมให้เป็นจำนวนเต็ม - VB6

Category »  VB 6/VB.Net
โดย : Webmaster เมื่อ 5/2/2554   เวลา: 19:58
(อ่าน : 46789) 
ข้้อมูลคอมพิวเตอร์มันไม่ได้อยู่ในรูปแบบของเลขฐาน 10 แต่มันจะอยู่ในลักษณะของ Binary หรือ เลขฐาน 2 ซึ่งปกติแล้วเรามักจะใช้ 0 หรือ 1 มาอธิบายกัน (จริงๆแล้วมันอาศัยระดับความต่างศักย์ไฟฟ้า หรือ ความเข้มของสนามแม่เหล็ก เป็นต้น) ... ซึ่งตอนที่ผมเรียนวิชา Numerical Method หรือ วิีธีการเชิงตัวเลข ก็ยิ่งทำให้เข้าใจลักษณะของการจัดเก็บข้อมูลได้มากขึ้น ตัวอย่างง่ายๆเช่น ตัวเลข 1.50 พอมันไปอยู่ในคอมพิวเตอร์มันอาจจะเป็น 1.4999999999 ก็ได้ แต่ครั้นพอนำมาแสดงผล มันจะเกิดการปัดเศษ (Rounding) ทำให้ได้ค่าเท่ากับ 1.50 แทนยังไงล่ะครับ (โดยใช้ Format(Value, "0.00") เข้าช่วย) ... มาว่ากันถึงเรื่องตัวแปลภาษา ซึ่งแต่ละตัวก็จะใช้ Algorithm ที่แตกต่างกันไปในการปัดเศษ ... สำหรับใน Visual Basic จะใช้ Banker's Rounding (อ่านรายละเอียดเพิ่มเติมที่นี่) คือ หากต่ำกว่า 4 ปัดเศษทิ้ง หากสูงกว่า 6 ก็ให้ปัดขึ้น แต่มันเกิดปัญหากับค่า 5 นี่แหละจะให้มันปัดขึ้น หรือ ปัดทิ้งดีล่ะ ... แอ่น แอ้น
    Banker's Rounding มันมีหลักการคิดปัดเลขทศนิยมดังนี้ คือ
  • ถ้าตัวเลขข้างหน้า 5 หากเป็นเลขคี่ ก็ให้ปัดขึ้น หากไม่ใช่ก็ให้ปัดเศษทิ้ง
    ตัวอย่าง ...
  • Visual Basic 6 ใช้ Round Function
    เป็นฟังค์ชั่น (หรือคำสั่งภายใน) ที่จะคืนค่าการปัดเศษตามจำนวนตำแหน่งจุดทศนิยมที่ต้องการ
    Round(expression [,numdecimalplaces])
    ? Round(10.15, 1)
    10.2 <-- หน้าเลข 5 เป็น 1 (เลขคี่) ปัดขึ้น
    ? Round(10.25, 1)
    10.2 <-- หน้าเลข 5 เป็น 2 (เลขคู่) ปัดเศษทิ้ง
    ? Round(10.35, 1)
    10.4 <-- หน้าเลข 5 เป็น 3 (เลขคี่) ปัดขึ้น
    ? Round(10.45, 1)
    10.4 <-- หน้าเลข 5 เป็น 4 (เลขคู่) ปัดเศษทิ้ง
  • แล้วมันใช่หรือเปล่า ...
    ? Round(134.425, 2)
    134.43 <-- ผิดมั้ยล่ะครับ ... ก็ข้างหน้า 5 มันเป็นเลขคู่ แล้วทำไมมันปัดเศษขึ้น
    ? Round (1.425, 2)
    1.42 <-- แบบนี้ถูก
  • ลองดูการแก้ปัญหา
    สำหรับ VB6
    ? Round(CDec(134.425), 2)
    134.42
    สำหรับ VB.Net
    ? Math.Round(CDec(134.425), 2)
    134.42D
    ? Math.Round(Decimal.Parse(134.425), 2)
    134.42D
    ปัญหาต่อมา ...
  • การปัดเศษเพื่อให้เป็นเลขจำนวนเต็ม
    ? Round(12.5, 0)
    12 <--ทำไมมันไม่ปัดขึ้น
    ความเป็นจริงแล้ว มันควรจะเป็น 13 ไม่ใช่ 12 ซิ ... (คงจะคิดกันว่าข้างหน้าเลข 5 มันเป็นเลขคู่ ชิมิๆๆ)
    งั้นเราลองมาดูแบบนี้
    ? Round(11.5, 0)
    12 <-- มันปัดขึ้น
    ถามว่า ... คุณเห็นดีแล้วหรือทองก้อนเจ้าขา ที่คุณนำเมียน้อยมา 55555+
    ฟังเพลงน้ำตาเมียหลวง - ผ่องศรี วรนุช ... ชอบจริงๆเลยเพลงนี้ครับพี่น้อง
    ลองมาสมมุติตัวเลขเล่นๆกัน ... โดยการเขียนโปรแกรมเพื่อตัดเกรดแบบอิงกลุ่ม
    คะแนน 54 - 58 ได้เกรด C
    คะแนน 59 - 62 ได้เกรด C+
    คนที่ได้ 53.5 ก็จะเลื่อนขึ้นมาที่เกรด C แต่คนที่ได้ 58.5 กลับไม่ได้เลื่อนเกรดไปที่ C+ ...
    หากประมวลผลออกมาแบบนี้ มีหวังนักศึกษาด่า (ลับหลัง) เละแหละครับ เพราะมันเกิดความไม่เป็นธรรมนี่นา
  • ลองดูการแก้ปัญหา
    ? Format(12.5, "0")
    13
    ? Round(12.5 + 0.000000000000005, 0) <-- ตัวนี้ 5E-15 ครับ หรือลอง Round(12.5 + 5E-16, 0) ดูครับ
    13
บางคนอาจจะคิดว่านี่เป็น Bug ของ VB6 (ฮาตรึมล่ะ) VB.Net ก็เป็นเหมือนกันครับ ลองใช้ Math.Round() ได้เลย แล้วมันเป็นที่คอมพิวเตอร์ หรือ ตัวแปลภาษา กันล่ะเนี่ย หากสนใจใคร่รู้ ... คลิ๊กอ่านได้ที่นี่ครับ
หมายเหตุ: ที่บอกว่าผลลัพธ์ VB6 กับ VB.Net มันเหมือนกัน หมายความว่าใช้คำสั่ง Round แต่เพียงอย่างเดียวเท่านั้นน่ะครับ
    ผมมีโค้ดเล็กๆให้ดูเรื่องของชนิดความเที่ยงตรงของข้อมูล (Single/Double Precision)
  • Dim X As Double
    Dim i As Integer

    X = 0
    For i = 1 To 17
        X = X + 10 / 17
    Next i

    If X = 10 Then
        MsgBox X & " = 10"
    Else
        MsgBox X & " <> 10"
    End If
  • ผลที่ได้
    ? X
    10 <-- ตอนที่ Debug ออกมาดู บรรทัด If X = 10 Then

    การ Debug เพื่อดูผลจริง

    งงน่ะจังงัง ... แบบนี้คอมพิวเตอร์สับสนเลย เอิ๊กๆๆๆๆ
    ลองปรับรูปแบบให้ X = Format(X, "0") หรือลองเปลี่ยน X เป็น Single ดูว่าผลที่ได้มันจะเป็นอย่างไร
  • คราวนี้มาดู Visual Basic 2008 กันบ้าง

    ดูจาก VB.Net จะเห็นผลได้อย่างชัดเจนเลยว่า ในหน่วยความจำไม่ได้เก็บค่า 10 แบบจำนวนเต็มเอาไว้ เพราะผลลัพธ์ที่ได้มันมาจากการปัดเศษ

    สำหรับ VB 2008 ... ก็เหมือนกับ VB6 (จับผิดตระกูล Dot Net ได้ คิกๆๆๆๆ)
    เฉลยให้เลยดีกว่า ... การแก้ปัญหา
    If Round(X, 1) = 10 Then ... หรือ
    If Format(X, "0") = 10 Then
    แบบนี้เขาเรียกว่าการเกิด Round Off Error หรือ ความผิดพลาดจากการปัดเศษ
  • ตัวอย่างของการจัดเก็บข้อมูลของคอมพิวเตอร์ ... และควรไปศึกษาเพิ่มเติม

    รูปแบบการจัดเก็บข้อมูลตัวเลขทางวิทยาศาสตร์ (ก็ตัวเลขที่มีจุดทศนิยมนั่นแหละครับ)
    ชนิดความเที่ยงตรงเชิงเดี่ยว (Single Precision) ขนาด 32 Bit
    คำอธิบายแบบย่อ:
    บิตซ้ายมือสุด คือ บิตเครื่องหมาย (Signed) หากเป็น 0 คือเลขบวก, หากเป็น 1 คือเลขลบ
    8 บิตถัดมาเรียกว่า Exponent คือ เลขยกกำลัง แบ่งออกเป็น
    1. หากไม่คิดเครื่องหมาย หรือ Unsigned (ค่า 0 กับจำนวนเต็มบวก) มีค่าเลขยกกำลังได้ระหว่าง 0 - 255
    2. หากคิดเครื่องหมาย หรือ Signed (-, 0 และ +) มีค่าเลขยกกำลังได้ระหว่าง -128 ถึง +127 (อ่านรายละเอียดเพิ่มเติมที่นี่)
    23 บิตสุดท้าย (Mantissa) คือส่วนเก็บเลขจุดทศนิยม แต่อยู่ในรูปแบบ Binary น่ะครับ
    สรุปสุดท้าย 1 Kg. = 1000 g. (เราคิดแบบฐาน 10) ... แต่สำหรับเลข Binary ขนาด 1 KByte. = 1024 Byte. (เราคิดแบบฐาน 2) ดังนั้นข้อมูลที่จัดเก็บในคอมพิวเตอร์ จะได้กราฟการเพิ่ม-ลดค่า ออกมาไม่เป็นสมการแบบเชิงเส้น (Non Linear Equation)
มาเขียนฟังค์ชั่นใช้งานเองดีกว่าครับ ... พี่น้อง
    แนวคิดฟังค์ชั่นของการปัดเศษเลขทศนิยมให้เป็นเลขจำนวนเต็ม
  • มีค่าชุดตัวเลขแบบทศนิยม เช่น 12.95 กับค่าที่ใช้เปรียบเทียบในการปัดเศษ เช่น 0.75
  • แยกชุดตัวเลขจำนวนเต็ม และ เลขทศนิยมออกจากกัน เช่น 12.95 ก็จะได้ 12 กับ 0.95
  • เอาชุดเลขทศนิยมที่ได้ (0.95) มาเปรียบเทียบกับค่าเลขทศนิยมที่ต้องการปัดเศษ (0.75)
      ทำการทดสอบค่าเลขทศนิยม กับค่าที่ต้องการจะปัดเศษ เช่น 0.95 >= 0.75
    • หากมีค่ามากกว่า หรือ เท่ากับ ก็ให้เพิ่มเลขจำนวนเต็มขึ้น 1
    • หากมีค่าน้อยกว่า ก็คืนค่าเลขจำนวนเต็มเดิมกลับคืนไป
  • คำเตือน ... โจทย์ข้อนี้คนละเรื่องกับคำสั่ง Int() หรือ Fix() น่ะครับ อิอิอิอิอิ
มาดูโค้ดกันเถอะ ...

Option Explicit

' #####################################################
' โปรแกรมย่อยแบบฟังค์ชั่น (สามารถคืนค่ากลับมาได้) เพื่อใช้ในการปัดเศษเลขทศนิยม
' ให้เป็นเลขจำนวนเต็ม มีการรับค่าเข้ามา 2 ค่าคือ
' NumberToRound ชุดตัวเลขที่ใช้ทดสอบในการปัดเศษ
' DoubleToRound (เป็น Optional) คือจะส่งค่ามาก็ได้ หรือไม่ส่งมาก็ได้ เพื่อใช้เปรียบเทียบการปัดเศษ
' แต่ถ้าหากไม่ส่งค่ามา ตัวแปรตัวนี้จะมีค่าจะเท่ากับ 0 ไปโดยปริยาย
' และมีการคืนค่ากลับเป็นแบบเลขจำนวนเต็ม Long
' #####################################################
Public Function RoundNumber( _
    ByVal NumberToRound As Double, _
    Optional ByVal DoubleToRound As Double = 0 _
    ) As Long
    
    ' ประกาศตัวแปรแบบ Array เพื่อแยกส่วนของเลขจำนวนเต็ม และ เลขทศนิยมออกจากกัน
    Dim Parts() As String
    
    ' ตรวจสอบก่อนว่าชุดตัวเลขที่ส่งมานี้เป็นเลขทศนิยมหรือไม่ หากไม่ใช่ให้เด้งออกไปจากโปรแกรมย่อยทันที
    ' โดยใช้ฟังค์ชั่น (หรือคำสั่ง) InStr ทดสอบหาเครื่องหมายจุดทศนิยม
    ' เริ่มต้นจากตำแหน่งที่ 1 ตามจำนวนตัวเลขของตัวแปร NumberToRound ที่ส่งมา
    ' หากหาไม่พบฟังค์ชั่นนี้จะคืนค่า 0 กลับมา แต่ถ้าหากพบก็จะคืนค่าตำแหน่งที่เจอจุดทศนิยมกลับมา
    If InStr(1, NumberToRound, ".") = 0 Then
        
        ' หากเป็นเลขจำนวนเต็ม (ไม่มีจุดทศนิยม) ก็ให้กลับออกจากโปรแกรมย่อย
        RoundNumber = NumberToRound
        
    Else
        ' เริ่มต้นการแยกชุดตัวเลขจำนวนเต็ม และ เลขทศนิยมออกจากกัน
        ' โดยใช้คำสั่ง Split(ชุดข้อความ, เครื่องหมายที่ใช้แยก)
        ' โดยที่ Parts(0) จะเก็บเลขจำนวนเต็มเอาไว้
        ' โดยที่ Parts(1) จะเก็บเลขทศนิยม
        Parts = Split(NumberToRound, ".")
        
        ' ทดสอบว่าชุดเลขทศนิยมมีค่ามากกว่าหรือเท่ากับ จำนวนเลขทศนิยมที่ต้องการปัดเศษให้เป็นเลขจำนวนเต็ม
        ' ใส่เครื่องหมายจุดทศนิยมนำหน้าก่อน จากนั้นใช้ CDbl เพื่อแปลงให้กลายเป็นเลขทศนิยม
        ' หากค่าเลขทศนิยมตัวหลักมากกว่า หรือเท่ากับค่าที่กำหนด เช่น 0.5 >= 0.5
        ' โจทย์ให้คิด: ต้องตรวจสอบค่า DoubleToRound ก่อนว่ามันน้อยกว่า 1 หรือไม่ ?
        If CDbl("0." & Parts(1)) >= DoubleToRound Then
        
            ' ให้เพิ่มค่าเลขจำนวนเต็มใน Parts(0) ขึ้นอีก 1 คือคำตอบสุดท้าย ... อิอิอิอิอิ
            RoundNumber = Parts(0) + 1
        
        Else
        
            ' หากไม่ใช่ให้คืนเลขจำนวนเต็มตัวเดิมใน Parts(0) กลับคืนไป
            RoundNumber = Parts(0)
            
        End If
    End If

End Function

การนำไปใช้งาน
Call RoundNumber(12.5)
Debug.Print RoundNumber(12.75, 0.75)

หรือจากหน้าต่าง Immediate Windows
? RoundNumber(12.5)
 13 
? RoundNumber(12.5, 0)
 13 
? RoundNumber(12.4, 0.5)
 12 
? RoundNumber(12.5, 0.5)
 13 
ฝากโจทย์อีกตัวให้คิดเป็นการบ้าน ... คำถามมีอยู่ว่าจะเขียนโปรแกรมอย่างไร โดยมีเงื่อนไขดังต่อไปนี้
  • หากเศษสตางค์อยู่ระหว่าง 1 - 25 สตางค์ ให้แสดงผลเป็น 25 สตางค์
  • หากเศษสตางค์อยู่ระหว่าง 26 - 50 สตางค์ ให้แสดงผลเป็น 50 สตางค์
  • หากเศษสตางค์อยู่ระหว่าง 51 - 75 สตางค์ ให้แสดงผลเป็น 75 สตางค์
  • หากเศษสตางค์อยู่ระหว่าง 76 - 99 สตางค์ ให้เลขจำนวนเต็มเพิ่มขึ้น 1 ส่วนเศษกลายเป็น 0 แทน
    ระหว่างค่า 1 - 75 สตางค์ (ทศนิยม) ค่าเลขจำนวนเต็ม (Integer) จะไม่มีการเปลี่ยนแปลงน่ะครับ

  • Conclusion:
    การศึกษาเรื่องราวของชนิดข้อมูล และ วิธีการจัดเก็บข้อมูลลงในคอมพิวเตอร์ให้ดีอย่างถ่องแท้ ก็จะสามารถช่วยให้เราเขียนโค้ดออกมาได้อย่างไม่มีปัญหา โดยเฉพาะสายงานทางด้านการเงิน งานด้านวิศวกรรม หรืองานทางด้านวิทยาศาสตร์ิ ที่ต้องใช้ความละเอียดของข้อมูลชนิดตัวเลขแบบทศนิยมสูงมาก ก็ต้องยิ่งระมัดระวังเป็นพิเศษอย่างยิ่ง ...

    จี ทู จี เน็ต ดอต คอม - g2gNet Dot Com
    เลขทะเบียนพาณิชย์อิเล็กทรอนิกส์ 0407314800231
    CopyLeft © 2004 - 2099 g2gNet.Com All rights reserved.
    Email: [email protected] หรือ โทร. 08-6862-6560