我的情况是我无法改变:一个数据库表(表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中的数量*单位是否超过3位小数(第1行会失败,第2行会通过):
if (CountDecimalPlaces(tableA.Qty * tableA.Unit) > 3)
{
return false;
}
tableB.TotalQty = tableA.Qty * tableA.Unit;
我如何实现CountDecimalPlaces(decimal value) {}
功能?
答案 0 :(得分:48)
您可以将舍入到3位小数的数字的值与原始值进行比较。
if (Decimal.Round(valueDecimal, 3) != valueDecimal)
{
//Too many decimals
}
答案 1 :(得分:14)
这适用于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(对于trully泛型函数,你需要类似“大整数”的东西)。
static decimal CountDecimalPlaces(decimal dec)
{
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;
}
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));
}
答案 2 :(得分:4)
这是一个非常简单的单行代码,用于在十进制中获取小数位数:
decimal myDecimal = 1.000000021300010000001m;
byte decimals = (byte)((Decimal.GetBits(myDecimal)[3] >> 16) & 0x7F);
答案 3 :(得分:3)
基础是知道如何测试是否有小数位,这是通过将值与其舍入值进行比较来完成的
double number;
bool hasDecimals = number == (int) number;
然后,要计算3个小数位,你只需要为你的数字乘以1000做同样的事情:
bool hasMoreThan3decimals = number*1000 != (int) (number * 1000)
答案 4 :(得分:2)
到目前为止提出的所有解决方案都是不可扩展的......如果你永远不会检查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;
}
答案 5 :(得分:2)
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));
答案 6 :(得分:2)
将一个带有3位小数的数字乘以10乘以3将得到一个没有小数位的数字。当模数% 1 == 0
时,它是一个整数。所以我提出了这个......
bool hasMoreThanNDecimals(decimal d, int n)
{
return !(d * (decimal)Math.Pow(10, n) % 1 == 0);
}
当n
小于(不等于)小数位数时,返回true。
答案 7 :(得分:1)
bool CountDecimalPlaces(decimal input)
{
return input*1000.0 == (int) (input*1000);
}
答案 8 :(得分:1)
这可能是一种更优雅的方式,但我会尝试
答案 9 :(得分:1)
基于@ RodH257解决方案的另一个选项,但作为扩展方法重新编写:
public static bool HasThisManyDecimalPlacesOrLess(this decimal value, int noDecimalPlaces)
{
return (Decimal.Round(value, noDecimalPlaces) == value);
}
然后您可以将其称为:
If !(tableA.Qty * tableA.Unit).HasThisManyDecimalPlacesOrLess(3)) return;
答案 10 :(得分:0)
你可以将它转换为字符串,只是做一个len函数,还是不能覆盖你的情况?
跟进问题: 300.4可以吗?
答案 11 :(得分:0)
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
答案 12 :(得分:0)
这是我的版本:
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