หนึ่งในโซลูชั่นที่ดีที่สุดสำหรับการหาจำนวนของตัวเลขหลังจุดทศนิยมจะแสดงในการโพสต์ของ burning_LEGION
นี่ฉันใช้ชิ้นส่วนจากบทความฟอรั่ม STSdb: จำนวนตัวเลขหลังจุดทศนิยม
ใน MSDN เราสามารถอ่านคำอธิบายต่อไปนี้:
"ตัวเลขทศนิยมคือค่าทศนิยมที่ประกอบด้วยเครื่องหมายเป็นค่าตัวเลขโดยแต่ละหลักในค่ามีค่าตั้งแต่ 0 ถึง 9 และตัวคูณมาตราส่วนที่ระบุตำแหน่งของจุดทศนิยมลอยตัวที่แยกอินทิกรัลและเศษส่วน ส่วนของค่าตัวเลข "
และนอกจากนี้ยังมี:
"การแทนค่าฐานสิบสองแบบไบนารีประกอบด้วยเครื่องหมาย 1 บิตจำนวนเต็ม 96 บิตและตัวคูณมาตราส่วนที่ใช้ในการหารจำนวนเต็ม 96 บิตและระบุว่าส่วนใดของมันเป็นเศษทศนิยมปัจจัยที่กำหนดคือ โดยปริยายเลข 10 ยกเป็นเลขชี้กำลังตั้งแต่ 0 ถึง 28 "
ในระดับภายในค่าทศนิยมจะแสดงด้วยค่าจำนวนเต็มสี่ค่า
มีฟังก์ชัน GetBits ที่เปิดเผยต่อสาธารณะสำหรับการเป็นตัวแทนภายใน ฟังก์ชันส่งคืนอาร์เรย์ int []:
[__DynamicallyInvokable]
public static int[] GetBits(decimal d)
{
return new int[] { d.lo, d.mid, d.hi, d.flags };
}
องค์ประกอบที่สี่ของอาร์เรย์ที่ส่งคืนประกอบด้วยตัวคูณมาตราส่วนและเครื่องหมาย และตามที่ MSDN กล่าวว่าปัจจัยการปรับมาตราส่วนเป็นเลข 10 โดยปริยายยกขึ้นเป็นเลขชี้กำลังตั้งแต่ 0 ถึง 28 นี่คือสิ่งที่เราต้องการ
ดังนั้นจากการตรวจสอบทั้งหมดข้างต้นเราสามารถสร้างวิธีการของเรา:
private const int SIGN_MASK = ~Int32.MinValue;
public static int GetDigits4(decimal value)
{
return (Decimal.GetBits(value)[3] & SIGN_MASK) >> 16;
}
ที่นี่ SIGN_MASK ใช้เพื่อละเว้นเครื่องหมาย หลังจากตรรกะและเราได้เลื่อนผลลัพธ์ด้วย 16 บิตไปทางขวาเพื่อรับสเกลแฟคเตอร์จริง สุดท้ายค่านี้ระบุจำนวนหลักหลังจุดทศนิยม
โปรดทราบว่าที่นี่ MSDN ยังกล่าวว่าปัจจัยการปรับขนาดยังรักษาค่าศูนย์ต่อท้ายในเลขฐานสิบ เลขศูนย์ต่อท้ายไม่มีผลต่อค่าของเลขฐานสิบในการคำนวณทางคณิตศาสตร์หรือการเปรียบเทียบ อย่างไรก็ตามค่าศูนย์ต่อท้ายอาจถูกเปิดเผยโดยเมธอด ToString หากใช้สตริงรูปแบบที่เหมาะสม
โซลูชันนี้ดูเหมือนจะดีที่สุด แต่เดี๋ยวก่อนยังมีอีก โดยการเข้าถึงเมธอดส่วนตัวใน C #เราสามารถใช้นิพจน์เพื่อสร้างการเข้าถึงโดยตรงไปยังฟิลด์แฟล็กและหลีกเลี่ยงการสร้างอาร์เรย์ int:
public delegate int GetDigitsDelegate(ref Decimal value);
public class DecimalHelper
{
public static readonly DecimalHelper Instance = new DecimalHelper();
public readonly GetDigitsDelegate GetDigits;
public readonly Expression<GetDigitsDelegate> GetDigitsLambda;
public DecimalHelper()
{
GetDigitsLambda = CreateGetDigitsMethod();
GetDigits = GetDigitsLambda.Compile();
}
private Expression<GetDigitsDelegate> CreateGetDigitsMethod()
{
var value = Expression.Parameter(typeof(Decimal).MakeByRefType(), "value");
var digits = Expression.RightShift(
Expression.And(Expression.Field(value, "flags"), Expression.Constant(~Int32.MinValue, typeof(int))),
Expression.Constant(16, typeof(int)));
return Expression.Lambda<GetDigitsDelegate>(digits, value);
}
}
รหัสที่คอมไพล์นี้ถูกกำหนดให้กับฟิลด์ GetDigits โปรดทราบว่าฟังก์ชันได้รับค่าทศนิยมเป็น ref ดังนั้นจึงไม่มีการคัดลอกจริง แต่เป็นการอ้างอิงถึงค่าเท่านั้น การใช้ฟังก์ชัน GetDigits จาก DecimalHelper นั้นง่ายมาก:
decimal value = 3.14159m;
int digits = DecimalHelper.Instance.GetDigits(ref value);
นี่เป็นวิธีที่เร็วที่สุดในการหาจำนวนหลักหลังจุดทศนิยมสำหรับค่าทศนิยม