เล่นกับทศนิยม
🤔หัดเขียนโค้ดใหม่ๆการทำงานกับตัวเลขมีอะไรบ้างหว่า? แต่ละตัวทำงานยังไง? ข้อควรระวังมีอะไรบ้าง? ดช.แมวน้ำ มีคำตอบให้กั๊ฟป๋ม
ภาพจาก Microsoft Copilot — วิชาลอยฟ้าด้วยการตีขาในอากาศอย่างรวดเร็วทำให้มองไม่เห็นขา 😆
เนื้อหานี้เป็นส่วนหนึ่งของคอร์ส 🐣Procedural Programming ที่สอนเรื่องการเขียนโปรแกรมขั้นพื้นฐาน ซึ่งเพื่อนๆสามารถจิ้มไปดูเนื้อหาทั้งหมดได้เบย หรือถ้ายังนึกไม่ออกว่าจะเสพเรื่องอะไรดีก็ลองจิ้มดู 🛣️แนวทางเรียนรู้ ก่องก็ล่าย 😗
🤔เล่นกับเลขทศนิยมทำไง?
ม่ายบอก [] จากบทความ ประเภทของข้อมูล และ คำสั่งพื้นฐาน ที่ผ่านมาเราสามารถทำงานกับ ตัวเลขจำนวนเต็ม ได้แย้ว แต่ในโลกของเรายังมีพวก เลขทศนิยม ซึ่งเป็นสิ่งที่เราเลี่ยงไม่ได้ในการเขียนโปรแกรมอีกด้วย ซึ่งในภาษา C# เขาก็ได้เตรียม data type ที่เอาไว้ให้เราเล่นกับทศนิยมไว้แล้วตามตารางด้านล่าง( ̄▽ ̄)*
Data type | คำอธิบาย | ตัวย่อ | หมายเหตุ | ตัวอย่าง |
---|---|---|---|---|
float | เก็บเลขทศนิยมได้ 6-9 ตำแหน่ง | ต้องใส่ f ต่อท้ายตัวเลข | 3.14f | |
double | เก็บเลขทศนิยมได้ 15-17 ตำแหน่ง | ใช้ได้เลยไม่ต้องต่อท้าย | 3.14 | |
decimal | เก็บเลขทศนิยมได้ 28-29 ตำแหน่ง | ต้องใส่ 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 เป็นอะไรตามตัวอย่างด้านล่างงับ
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 | แปลงค่าในลงเว็บให้เป็น float | Convert.ToSingle("3.141") |
Convert.ToDouble | แปลงค่าในลงเว็บให้เป็น double | Convert.ToDouble("3.141") |
Convert.ToDecimal | แปลงค่าในลงเว็บให้เป็น decimal | Convert.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