[英]C# Check if a decimal has more than 3 decimal places?
我有一種無法更改的情況:一個數據庫表(表 A)接受 6 個小數位,而另一個表(表 B)中的相關列只有 3 個小數位。
我需要從 A 復制到 B,但如果 A 的小數位超過 3 位,額外的數據將丟失。 我無法更改表定義,但可以添加解決方法。 所以我試圖找出如何檢查小數點是否超過 3 個小數位?
例如
Table A
Id, Qty, Unit(=6dp)
1, 1, 0.00025
2, 4000, 0.00025
Table B
Id, TotalQty(=3dp)
我希望能夠找出表 A 中的 Qty * Unit 是否有超過 3 位小數(第 1 行會失敗,第 2 行會通過):
if (CountDecimalPlaces(tableA.Qty * tableA.Unit) > 3)
{
return false;
}
tableB.TotalQty = tableA.Qty * tableA.Unit;
我將如何實現CountDecimalPlaces(decimal value) {}
函數?
您可以將四舍五入到小數點后 3 位的數字的值與原始值進行比較。
if (Decimal.Round(valueDecimal, 3) != valueDecimal)
{
//Too many decimals
}
這適用於 3 個小數位,並且可以適用於通用解決方案:
static bool LessThan3DecimalPlaces(decimal dec)
{
decimal value = dec * 1000;
return value == Math.Floor(value);
}
static void Test()
{
Console.WriteLine(LessThan3DecimalPlaces(1m * 0.00025m));
Console.WriteLine(LessThan3DecimalPlaces(4000m * 0.00025m));
}
對於真正的通用解決方案,您需要在其部分“解構”十進制值 - 查看Decimal.GetBits了解更多信息。
更新:這是通用解決方案的簡單實現,適用於整數部分小於 long.MaxValue 的所有小數(對於真正的通用函數,您需要類似“大整數”的東西)。
static decimal CountDecimalPlaces(decimal dec)
{
Console.Write("{0}: ", dec);
int[] bits = Decimal.GetBits(dec);
ulong lowInt = (uint)bits[0];
ulong midInt = (uint)bits[1];
int exponent = (bits[3] & 0x00FF0000) >> 16;
int result = exponent;
ulong lowDecimal = lowInt | (midInt << 32);
while (result > 0 && (lowDecimal % 10) == 0)
{
result--;
lowDecimal /= 10;
}
return result;
}
static void Foo()
{
Console.WriteLine(CountDecimalPlaces(1.6m));
Console.WriteLine(CountDecimalPlaces(1.600m));
Console.WriteLine(CountDecimalPlaces(decimal.MaxValue));
Console.WriteLine(CountDecimalPlaces(1m * 0.00025m));
Console.WriteLine(CountDecimalPlaces(4000m * 0.00025m));
}
這是一個非常簡單的一行代碼,用於獲取 Decimal 中的小數位數:
decimal myDecimal = 1.000000021300010000001m;
byte decimals = (byte)((Decimal.GetBits(myDecimal)[3] >> 16) & 0x7F);
將一個有 3 個小數位的數字乘以 10 的 3 次方將得到一個沒有小數位的數字。 當模數% 1 == 0
時,它是一個整數。 所以我想出了這個...
bool hasMoreThanNDecimals(decimal d, int n)
{
return !(d * (decimal)Math.Pow(10, n) % 1 == 0);
}
當n
小於(不等於)小數位數時返回 true。
基礎知識是知道如何測試是否有小數位,這是通過將值與其舍入進行比較來完成的
double number;
bool hasDecimals = number == (int) number;
然后,要計算 3 個小數位,您只需要對乘以 1000 的數字執行相同的操作:
bool hasMoreThan3decimals = number*1000 != (int) (number * 1000)
到目前為止提出的所有解決方案都是不可擴展的......如果你永遠不會檢查 3 以外的值,那很好,但我更喜歡這個,因為如果需求改變了代碼來處理它已經寫好了。 此解決方案也不會溢出。
int GetDecimalCount(decimal val)
{
if(val == val*10)
{
return int.MaxValue; // no decimal.Epsilon I don't use this type enough to know why... this will work
}
int decimalCount = 0;
while(val != Math.Floor(val))
{
val = (val - Math.Floor(val)) * 10;
decimalCount++;
}
return decimalCount;
}
carlosfigueira 解決方案需要檢查 0 否則“while ((lowDecimal % 10) == 0)”在使用 dec = 0 調用時會產生無限循環
static decimal CountDecimalPlaces(decimal dec)
{
if (dec == 0)
return 0;
int[] bits = Decimal.GetBits(dec);
int exponent = bits[3] >> 16;
int result = exponent;
long lowDecimal = bits[0] | (bits[1] >> 8);
while ((lowDecimal % 10) == 0)
{
result--;
lowDecimal /= 10;
}
return result;
}
Assert.AreEqual(0, DecimalHelper.CountDecimalPlaces(0m));
Assert.AreEqual(1, DecimalHelper.CountDecimalPlaces(0.5m));
Assert.AreEqual(2, DecimalHelper.CountDecimalPlaces(10.51m));
Assert.AreEqual(13, DecimalHelper.CountDecimalPlaces(10.5123456978563m));
另一個基於@RodH257 解決方案的選項,但作為擴展方法重新設計:
public static bool HasThisManyDecimalPlacesOrLess(this decimal value, int noDecimalPlaces)
{
return (Decimal.Round(value, noDecimalPlaces) == value);
}
然后,您可以將其稱為:
If !(tableA.Qty * tableA.Unit).HasThisManyDecimalPlacesOrLess(3)) return;
bool CountDecimalPlaces(decimal input)
{
return input*1000.0 == (int) (input*1000);
}
可能有一種更優雅的方法來做到這一點,但我會嘗試
Public Function getDecimalCount(decWork As Decimal) As Integer
Dim intDecimalCount As Int32 = 0
Dim strDecAbs As String = decWork.ToString.Trim("0")
intDecimalCount = strDecAbs.Substring(strDecAbs.IndexOf(".")).Length -1
Return intDecimalCount
End Function
你能把它轉換成一個字符串然后只做一個 len 函數還是不能涵蓋你的情況?
后續問題:300.4 可以嗎?
這是我的版本:
public static int CountDecimalPlaces(decimal dec)
{
var a = Math.Abs(dec);
var x = a;
var count = 1;
while (x % 1 != 0)
{
x = a * new decimal(Math.Pow(10, count++));
}
var result = count - 1;
return result;
}
我首先嘗試了@carlosfigueira/@Henrik Stenbæk
,但他們的版本不適用於324000.00m
測試:
Console.WriteLine(CountDecimalPlaces(0m)); //0
Console.WriteLine(CountDecimalPlaces(0.5m)); //1
Console.WriteLine(CountDecimalPlaces(10.51m)); //2
Console.WriteLine(CountDecimalPlaces(10.5123456978563m)); //13
Console.WriteLine(CountDecimalPlaces(324000.0001m)); //4
Console.WriteLine(CountDecimalPlaces(324000.0000m)); //0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.