Skip to main content

เล่นกับทศนิยม

🤔หัดเขียนโค้ดใหม่ๆการทำงานกับตัวเลขมีอะไรบ้างหว่า? แต่ละตัวทำงานยังไง? ข้อควรระวังมีอะไรบ้าง? ดช.แมวน้ำ มีคำตอบให้กั๊ฟป๋ม

banner

ภาพจาก Microsoft Copilot — วิชาลอยฟ้าด้วยการตีขาในอากาศอย่างรวดเร็วทำให้มองไม่เห็นขา 😆

อ่านต่อ

เนื้อหานี้เป็นส่วนหนึ่งของคอร์ส 🐣Procedural Programming ที่สอนเรื่องการเขียนโปรแกรมขั้นพื้นฐาน ซึ่งเพื่อนๆสามารถจิ้มไปดูเนื้อหาทั้งหมดได้เบย หรือถ้ายังนึกไม่ออกว่าจะเสพเรื่องอะไรดีก็ลองจิ้มดู 🛣️แนวทางเรียนรู้ ก่องก็ล่าย 😗

🤔เล่นกับเลขทศนิยมทำไง?

ม่ายบอก []( ̄▽ ̄)* จากบทความ ประเภทของข้อมูล และ คำสั่งพื้นฐาน ที่ผ่านมาเราสามารถทำงานกับ ตัวเลขจำนวนเต็ม ได้แย้ว แต่ในโลกของเรายังมีพวก เลขทศนิยม ซึ่งเป็นสิ่งที่เราเลี่ยงไม่ได้ในการเขียนโปรแกรมอีกด้วย ซึ่งในภาษา C# เขาก็ได้เตรียม data type ที่เอาไว้ให้เราเล่นกับทศนิยมไว้แล้วตามตารางด้านล่าง

Data typeคำอธิบายตัวย่อหมายเหตุตัวอย่าง
floatเก็บเลขทศนิยมได้ 6-9 ตำแหน่ง
f
ต้องใส่ f ต่อท้ายตัวเลข3.14f
doubleเก็บเลขทศนิยมได้ 15-17 ตำแหน่ง
d
ใช้ได้เลยไม่ต้องต่อท้าย3.14
decimalเก็บเลขทศนิยมได้ 28-29 ตำแหน่ง
m
ต้องใส่ m ต่อท้ายตัวเลข3.14m

ไหนๆลองเอามาเขียนโค้ดจริงๆดูซิ โดยป๋มจะใส่ตัวเลขทศนิยม 30 ตำแหน่งเข้าไป แล้วลองดูผลลัพท์ตามด้านล่าง

float  small  = 0.123456789012345678901234567890f;
double medium = 0.123456789012345678901234567890;
decimal large = 0.123456789012345678901234567890m;

Console.WriteLine($"float: {small}");
Console.WriteLine($"double: {medium}");
Console.WriteLine($"decimal: {large}");

ผลลัพท์

float:   0.12345679
double: 0.12345678901234568
decimal: 0.1234567890123456789012345679

จากผลลัพท์ด้านบนจะเห็นว่า float, double, decimal จะมีข้อจำกัดในการเก็บค่าทศนิยมตามที่เขียนไว้ในตารางด้านบน และโปรแกรมจะจัดการปัดเศษให้อัตโนมัติอีกด้วย

🤨แล้วถ้าไม่ใส่ตัวอักษรต่อท้ายอ่ะ?
คอมก็จะระเบิดปุ้ง (´▽`ʃ♡ƪ) ถ้าเราไม่ใส่ตัวอักษรกำกับไว้ด้านหลังตัวเลข หรือลืมใส่ คอมจะให้เลขทศนิยมเป็น double เป็นพื้นฐาน ซึ่งสามารถพิสูจน์ได้จากโค้ดด้านล่างนี้

var number = 0.123456789012345678901234567890;
Console.WriteLine(number);

ผลลัพท์

0.12345678901234568

🤨จะรู้ได้ไงว่านั้นเป็น double จริงๆ?
เราหลับตาเชื่อมป๋มไปเต๊อะ ( ̄▽ ̄) ถ้าเราอยากรู้ว่าตัวแปรนั้นๆมี data type เป็นอะไร เราสามารถใช้คำสั่ง .GetType() ต่อท้ายตัวแปรนั้นๆได้เลย ตามโค้ดตัวอย่างด้านล่าง

var number = 0.123456789012345678901234567890;
var typeOfNumber = number.GetType();
Console.WriteLine(typeOfNumber);

ผลลัพท์

System.Double

จากตัวอย่างด้านบนก็จะเห็นว่าตัวแปร number นั้นมี data type เป็น System.Double หรือ double นั่นเองกั๊ฟ หรือจะใช้อีกวิธีที่ง่ายกว่านั้นคือ ให้เราเลื่อนเมาส์เข้าไปอยู่เหนือคำว่า var แล้วมันจะมี popup เด้งมาบอกว่าตัวแปรนั้นๆมี data type เป็นอะไรตามตัวอย่างด้านล่างงับ

show-datatype

เกร็ดความรู้

double กับ System.Double จริงๆมันคือตัวเดียวกันเด๊ะๆเลย โดยคำว่า double มันคือตัวย่อให้เราไม่ต้องไปพิมพ์ System.Double ยาวๆนั่นเอง ซึ่งเราจะใช้ตัวไหนก็ได้ไม่มีผลใดๆทั้งสิ้น และทาง Microsoft ก็แนะนำให้ใช้คำว่า double ไปเยย ส่วนถ้าเพื่อนๆแอบซนเอาเมาส์ไปชี้ตัว var ที่เก็บข้อมูลเป็น string ก็จะเห็นชื่อเป็น System.String ซึ่งก็เป็นเรื่องเดียวกับที่อธิบายมานี้เยย และ แน่นอนว่าเราควรใช้คำว่า string เช่นเดียวกัลลลลล 😘

แต่ไม่ได้หมายความว่าทุกตัวจะชื่อตรงตัวเสมอนะ เช่นเจ้า int จะแปลกๆหน่อยเพราะชื่อเต็มๆของมันคือ System.Int32 และ float จะเป็น System.Single งับ ส่วนสาเหตุที่มันมีชื่อแปลกๆเป็นเพราะ Microsoft เขาไม่ได้มีแค่ภาษา C# อย่างเดียว เขาพัฒนาหลายภาษา ซึ่งแต่ละภาษาก็ทำงานร่วมกันได้ด้วย เขาเลยมีชื่อกลางเอาไว้ใช้คุยข้ามภาษากัน นั่นก็คือเจ้า System.Int32 อะไรพวกนั้นนั่นแหละ 😅

🔢การแปลงค่าตัวเลข

จากฟามรู้ที่เรียนกับป๋มมา ของที่เกี่ยวกับตัวเลขในการเขียนโค้ดตอนนี้ก็จะมีทั้งหมด 2 กลุ่มใหญ่ๆนั่นคือ เลขจำนวนเต็ม และ เลขทศนิยม ตามรูปด้านล่าง

นอกจากนี้เราก็จะรู้ว่า ตัวแปรมันรักเดียวใจเดียว ซึ่งหมายความว่าตัวแปรที่ถูกสร้างขึ้นมานั้นจะไม่สามารถถูกเปลี่ยน data type ได้ ...แต่สำหรับตัวเลขนั้น ระบบสามารถแปลงค่าตัวเลขข้าม data type ให้เราได้ โดยมีเงื่อนไขว่าประเภทตัวแปรที่เป็น value จะต้องมีขนาดเล็กกว่าหรือเท่ากันกับประเภทตัวแปรฝั่งรับค่า และ การแปลงทศนิยมด้วยกันเองสามารถทำได้แค่ float ไปเป็น double เท่านั้น ตามตัวอย่างด้านล่าง (ขนาดของตัวแปรดูได้จากรูปด้านบน)

รูปแบบการใช้งาน
ตัวแปรฝั่งรับค่า = value;

ตัวอย่างที่ตรงเงื่อนไข โปรแกรมแปลงค่าให้อัตโนมัติได้เยย

int money = 100;        // ทำได้เพราะขนาดเท่ากัน
float small = money; // ทำได้เพราะขนาดเท่ากัน
double medium = small; // ทำได้ value มีขนาดเล็กกว่า

อธิบาย

  • บรรทัดที่ 1 → ตัวแปรฝั่งรับค่า int money มีขนาด เท่ากันกับ ตัวแปรฝั่งส่งค่า 100 เพราะเลข 100 ระบบมองเป็น int
  • บรรทัดที่ 2 → ตัวแปรฝั่งรับค่า float small มีขนาด เท่ากันกับ ตัวแปรฝั่งส่งค่า int money
  • บรรทัดที่ 3 → ตัวแปรฝั่งรับค่า double medium มีขนาด ใหญ่กว่า ตัวแปรฝั่งส่งค่า float small

หากเรานำตัวแปร money, samll, medium ไปพิมพ์ออกหน้าจอ เราจะได้เลข 100 หมดเยย

ตัวอย่างที่ไม่ตรงเงื่อนไข โปรแกรมไม่สามารถแปลงค่าให้เราได้

double medium = 222.22; // ขนาดเท่ากัน
decimal large = medium; // ERROR ทำไม่ได้ เพราะ เป็นข้อยกเว้น
decimal small = medium; // ERROR ทำไม่ได้ เพราะ value มีขนาดใหญ่กว่า
int money = medium; // ERROR ทำไม่ได้ เพราะ value มีขนาดใหญ่กว่า

การที่โปรแกรมแปลงค่าให้เราแบบอัตโนมัตินี้ ในภาษาเดฟเรียกว่า Implicit conversion นั่นเองกั๊ฟป๋ม

🤨งั้นเราก็ใช้แต่ double จะได้ไม่มีปัญหางี้เหรอ?
ก็ไม่ต้องขนาดนั้นหรอก ในเมื่อโปรแกรมไม่ยอมทำให้อัตโนมัติ งั้นเราก็ทำเองด้วย การระบุประเภทตัวแปรด้วยตัวเอง หรือเราเรียกว่าการ ข่มขืน Casting โดยการให้ใส่เขียนประเภทตัวแปรที่ต้องการไว้ด้านหน้า value แล้วใส่เครื่องหมายวงเล็บ () ลงไปนั่นเอง ตามตัวอย่างด้านล่าง

double almostFour = 3.99999999;
int money = (int)almostFour; // แปลงค่าให้เป็น int
Console.WriteLine(money);

ผลลัพท์

3

การ Casting จะช่วยแปลง data type ให้เราได้ก็จริงแต่ การ Casting ก็ต้องแลกมากับข้อมูลที่ได้จะไม่สมบูณ์ ตามตัวอย่างด้านบน เลขทศนิยมถูกตัดหายไปเลยโดยที่ไม่มีการปัดเศษใดๆด้วย ซึ่งเรื่องนี้ในภาษาเดฟเราเรียกว่าการทำ Explicit conversion หรือการ ข่มขืน ระบุประเภทตัวแปรด้วยมือนั่นเอง

เกร็ดความรู้

จริงอยู่ว่าการใช้ double หรือ decimal ไปเลยมันสามารถเก็บค่าได้ทั้งเลขจำนวนเต็มและเลขทศนิยมหลายตำแหน่ง ซึ่งดีกว่า int และ float เสียอีก แต่มันแลกมากับ ตัวแปรขนาดใหญ่ก็จะใช้พื้นที่ในหน่วยความจำมากขึ้นตามตัว เปรียบง่ายๆ เราจะสร้างห้องน้ำในบ้านที่มีขนาดเท่าสนามฟุตบอลก็ได้นะ แต่ค่าใช้จ่ายก็จะสูงตาม แต่มันจะดีกว่าไหมถ้าเราสร้างเท่าที่จำเป็นจะใช้เท่านั้น? ซึ่งในช่วงแรกที่เขียนโปรแกรมเราจะไม่ค่อยเจอปัญหาเรื่องนี้ เพราะเราเขียนบนเครื่องคอม แต่ลองนึกดูถ้าโปรแกรมของเราไปทำงานบทเครื่องที่มีทรัพยากรจำกัดหล่ะ? แบบอุปกรณ์ IoT นาฬิกา, แหวน, หูฟัง บลาๆ และนอกจากพื้ยที่แล้วจริงๆมันก็มีผลกับเรื่อง performance ของโปรแกรมเราด้วยนะ ในกรณีที่เราต้องรีด performance สูงๆ จริงๆ เราต้องรีดระดับ bit, fix size ต่างๆเลย ดังนั้นฝึกการใช้ตัวแปรที่เหมาะสมจะดีกว่าในระยะยาวฮั๊ฟ

หมายเหตุ การสร้างตัวแปรเป็น double หรือ decimal ไม่ได้ทำให้มีปัญหาขนาดนั้นหรอกนะแต่เป็นเรื่องการเลือกใช้ของให้เหมาะสมกับงานต่างหาก 😌

สรุปการแปลงค่าตัวเลขแบบอัตโนมัติ (Implicit conversion) ที๋โปรแกรมสามารถทำให้เราได้เลย ตามรูปด้านล่าง หรือจำง่ายๆว่า int แปลงได้ทุกแบบ และ float แปลงได้แค่ double เท่านั้น มีแค่นี้เยย นอกนั้นต้อง ข่มขืน Casting เท่านั้น 😅

🅰️การแปลงตัวอักษรเป็นตัวเลข

จากบทความ ประเภทของข้อมูล เราจะได้เรียนการแปลง ตัวอักษร → ตัวเลข ด้วยคำสั่ง Convert กันแย้ว ซึ่งในคราวนี้เราก็ได้เจอ 3 ประเภทตัวแปรใหม่ (float, double, decimal) ดังนั้นเราก็จะมาอัพเดทคำสั่งให้ครบทุกประเภทตัวแปรกันตามด้านล่างเยย

คำสั่งคำอธิบายตัวอย่าง
Convert.ToSingleแปลงค่าในลงเว็บให้เป็น floatConvert.ToSingle("3.141")
Convert.ToDoubleแปลงค่าในลงเว็บให้เป็น doubleConvert.ToDouble("3.141")
Convert.ToDecimalแปลงค่าในลงเว็บให้เป็น decimalConvert.ToDecimal("3.141")
float small = Convert.ToSingle("3.141");
double medium = Convert.ToDouble("3.141");
decimal large = Convert.ToDecimal("3.141");

🥲จำยากอ่ะ
( ̄y▽, ̄)╭ จดเอาจิ อย่าไปจำ เจ้าคำสั่ง Convert เวลาใช้งาน เราจะต้องเลือกให้ตรงตาม System type เสมอ ซึ่งเราก็ต้องมาท่องว่า int มันชื่อ Int32 หรือ float มันชื่อ Single ซึ่งมันไม่ใช้เรื่องสนุกที่เราต้องมานั่งจำอะไรเทือกนี้ ดังนั้น ดช.แมวน้ำ จะพาเล่นอีกวิธีที่ง่ายกว่านั้นนั่นคือคำสั่ง .Parse() ซึ่งเราต้องระบุประเภทตัวแปรก่อนใช้งาน ตามด้านล่าง

รูปแบบการใช้งาน
DataType.Parse( ตัวอักษรที่ต้องการจะแปลง );

ตัวอย่างการใช้งาน

int money = int.Parse("100");
float small = float.Parse("3.141");
double medium = double.Parse("3.141");
decimal large = decimal.Parse("3.141");
ข้อความระวัง

การแปลงตัวอักษรมาเป็นตัวเลขนั้น ถ้าระบบสามารถไม่สามารถทำ Implicit Conversion กับข้อมูลนั้นๆได้ ก็จะเกิด error ขึ้นทันที โดยไม่มีการแจ้งเตือนล่วงหน้าใดๆเลย ตามตัวอย่างด้านล่าง ที่แปลงเลขทศนิยมมาเป็นตัวเลขจำนวนเต็ม

int money = int.Parse("3.141");

ERROR
Unhandled exception. System.FormatException: The input string '3.141' was not in a correct format.

💀ป้องกันแอพเด้งจากการแปลงค่า

ในการแปลงค่า ตัวอักษร → ตัวเลข มันมีโอกาสูงมากที่จะทำให้โปรแกรมของเราพัง เช่น ผู้ใช้ใส่ค่าที่ไม่ใช่ตัวเลขเข้ามา หรือ ระบบไม่สามารถแปลงค่าให้แบบอัตโนมัติได้ ตามตัวอย่างด้านล่าง

int input1 = int.Parse("Hello"); // ERROR แปลงข้อความเป็นตัวเลขไม่ได้
int input2 = int.Parse("3.141"); // ERROR แปลงทศนิยมเป็นจำนวนเต็มไม่ได้

เพื่อป้องกันไม่ให้โปรแกรมพัง เราสามารถใช้คำสั่ง .TryParse() เพื่อให้โปรแกรมพยายามแปลงค่าให้เราโดยไม่ให้เกิด error กรณีแปลงค่าไม่ได้ตัวแปรของเราจะมีค่าเป็น default value ตาม data type นั้นๆ โดยมีรูปแบบการใช้งานตามตัวอย่างด้านล่าง

รูปแบบการใช้งาน
ประเภทข้อมูล.TryParase( ข้อความที่จะแปลง, out ตัวแปรที่จะนำมาเก็บข้อมูล );

กลุ่มตัวเลขทั้งหมดจะมีค่า default value เป็น 0 นะกั๊ฟ เช่นพวก int, float, double, decimal ที่อ่านมาใช่หมดเยย ลองดูได้จากตัวอย่างด้านล่างนี้

  • ตัวอย่าง 1 — แปลงข้อความที่ไม่ใช่ตัวเลข ระบบไม่สามารถแปลงให้ได้ มันเลยกำหนดค่าเป็น 0 ให้
    int input;
    int.TryParse("Hello", out input);
    Console.WriteLine(input);

    ผลลัพท์

    0
  • ตัวอย่าง 2 — แปลงข้อความเลขทศนิยมไปเป็นเลขจำนวนเต็ม ระบบไม่สามารถแปลงให้ได้ มันเลยกำหนดค่าเป็น 0 ให้เรา
    int input;
    int.TryParse("3.141", out input);
    Console.WriteLine(input);

    ผลลัพท์

    0
  • ตัวอย่าง 3 — แปลงข้อความเลขจำนวนเต็ม ระบบทำได้ไม่มีปัญหาใดๆ
    int input;
    int.TryParse("100", out input);
    Console.WriteLine(input);

    ผลลัพท์

    100

นอกจากในตัวอย่างที่ใช้ int.TryParse() แล้ว เรายังสามารถใช้ TryParse() กับประเภทตัวแปรอื่นๆได้ด้วยนะ เช่น float, double, decimal ตามด้านล่างนี้เยย

float small;
float.TryParse("3.14159265358979323846264338327", out small);

double medium;
double.TryParse("3.14159265358979323846264338327", out medium);

decimal large;
decimal.TryParse("3.14159265358979323846264338327", out large);

Console.WriteLine(small);
Console.WriteLine(medium);
Console.WriteLine(large);

ผลลัพท์

3.1415927
3.141592653589793
3.1415926535897932384626433833
เกร็ดความรู้

นอกจากคำสั่ง TryParse เพื่อป้องกันโปรแกรมพังแล้ว จริงๆเราก็จะมีคำสั่ง try/catch เพื่อรับมือกับแอพพังเหมือนกัน แต่ๆๆๆๆๆ ดช.แมวน้ำ ขอเตือนก่อนว่า ถ้าเป็นไปได้ให้ใช้คำสั่ง try/catch ให้น้อยที่สุด หรือเลี่ยงได้เลี่ยงเลย เนื่องจากประสิทธิภาพการทำงานของโปรแกรมจะแย่ลงมากๆ แย่ลงในเชิงคอมพิวเตอร์ ซึ่งมนุษย์ไม่รู้สึกหรอก ส่วนเราจะเลี่ยงยังไง หรือมีปัญหาจริงๆไหม เดี๋ยวอ่านไปจนถึงบท try/catch ป๋มจะเฉลยให้ดูกันงับ 😎

ส่วนการใช้ TryParse() จริงๆมันมีลูกเล่นอีกอยู่นะ แต่เดี๋ยวขอเอาไปรวมกับบทความที่สอนเรื่อง if-else นะ 😎

🥳สรุป

ในบทนี้เราก็จะได้รู้ว่าในโลกของโปรแกรมนั้นเรื่อง เลขทศนิยม มันมีการแบ่งย่อยลงไปอีก 3 ตัวไล่ตามความละเอียดของจำนวนทศนิยม เป็น float, double, decimal ตามลำดับ ซึ่งพวกตัวเลขก็มีความสามารถในการแปลงค่าข้าม data type ได้แบบอัตโนมัติ Implicit conversion ส่วนพวกที่แปลงไม่ได้เราก็ต้องทำ casting หรือ Explicit conversion ให้มันด้วยมือ และการแปลงค่าจากตัวอักษรมาเป็นตัวเลขเราก็สามารถใช้คำสั่ง Convert ได้เหมือนปรกติ แต่จะต้องเลือกชื่อจาก System type ให้ถูก หรือง่ายกว่านั้นเราสามารถใช้คำสั่ง .Parse() ได้เช่นกัน แต่จะมีบางกรณีที่มันแลงค่าไม่ได้แล้วทำให้โปรแกรมพัง ดังนั้นเลยแนะนำให้ใช้ .TryParse() แทนนั่นเอง ... ฟู่วเยอะจุงบทนี้ 😝


🎮ท้าทายฟามรู้

🤔เราจะแปลงค่าข้อความนี้ "100.00" ด้วยคำสั่งไหนดีเอ่ย

🤔เราควรใช้ data type ไหนในการเก็บค่า 999.111222333444 ดีเอ่ย

🤔ถ้าเอาค่า 777.888 (float) ไปใส่ในตัวแปรที่เป็น decimal จะเกิดอะไรขึ้นเอ่ย


  • ⌛ตัวอย่างการใช้ ++--
  • ⌛ตัวอย่างการใช้ +=
  • ⌛ลำดับการคำนวณทางคณิตศาสตร์ ท้าทายฟามรู่ 1 + 2 * 3 - 6 / 3