我知道.NET 有一个内置的,但它是一个外部调用。有谁知道为什么?
但实际的问题是如何从头开始实现截断,用户将能够指定要保留多少位数字?将一个数字乘以 100 然后除以相同的数量就足够了吗?还是有更好的实现方式?
就像是:
Truncate(12.3456789, 3);
// returns 12.345
您可能想查看 IEEE 浮点整数。
然后,您可以使用unsafe
代码来修改数字,例如:
unsafe
{
double* pValue = &value;
var asLong = *(long*)pValue;
do whatever you want with asLong, e.g. bit-masking it, etc.;
}
至于“为什么”:我不知道,尽管共享源 CLI可能会提供线索。我的猜测是这可能是因为性能优化。
经典方式:
var x = 1.2345678;
var tr = 4;
var truncated = (int) (x * Math.Pow(10, tr)) / Math.Pow(10, tr);
将给出 1.2345;
这是我将如何做到的。在 C++ 中,我认为在 C# 中也是如此,您可以通过将浮点数转换为整数类型来获取浮点数的整数部分。
double Truncate (double num, int dig)
{
if (dig > 15) dig = 15; // Don't overflow
long p = Math.Pow (10, dig);
// Save the integer part, so that we don't overflow
long integer_part = (long)num;
// Fractional part * 10^dig
double frac = (num - Convert.ToDouble(integer_part)) * p;
long frac_trunc = (long)frac;
// Final result
double result = Convert.ToDouble(integer_part) + (Convert.ToDouble(frac_trunc) / p);
return result;
}
将一个数字乘以 100 然后除以相同的数量就足够了吗?
这应该可行,但要小心,因为数字很大或位数很多,你很容易溢出,它会给你带来奇怪的结果。
var result = Math.Round(12.3456789, 3);
目前尚不清楚您认为 Truncate 应该保留十进制值的原因。
.NET 中的默认方法由以下语句描述:
d的整数部分;也就是说,在任何小数位被丢弃后剩余的数字。
似乎您想要使用的是格式化双精度/十进制值的输出字符串和/或改用 Math.Round(double, int) 函数。
你可以只使用:
double num = 2.22939393; num = Convert.ToDouble(num.ToString("#0.000"));
从重复的问题之一:
public static decimal TruncateToDecimalPlace(this decimal numberToTruncate, int decimalPlaces)
{
decimal power = (decimal)(Math.Pow(10.0, (double)decimalPlaces));
return Math.Truncate((power * numberToTruncate)) / power;
}
我知道这仍然使用该Truncate
方法。我只提供了这段代码,因为您需要一种Truncate
方法来保留数字的十进制值,而默认的内置Truncate
方法则没有。
你总是可以使用这个:
Math.Round 不会SplitFractionDouble
根据我的判断调用
private static unsafe double InternalRound(double value, int digits, MidpointRounding mode) {
if (Abs(value) < doubleRoundLimit) {
Double power10 = roundPower10Double[digits];
value *= power10;
if (mode == MidpointRounding.AwayFromZero) {
double fraction = SplitFractionDouble(&value);
if (Abs(fraction) >= 0.5d) {
value += Sign(fraction);
}
}
else {
// On X86 this can be inlined to just a few instructions
value = Round(value);
}
value /= power10;
}
return value;
}
public static double Round(double value, int digits)
{
if ((digits < 0) || (digits > maxRoundingDigits))
throw new ArgumentOutOfRangeException("digits", Environment.GetResourceString("ArgumentOutOfRange_RoundingDigits"));
return InternalRound(value, digits, MidpointRounding.ToEven);
}
public static double Round(double value, MidpointRounding mode) {
return Round(value, 0, mode);
}
public static double Round(double value, int digits, MidpointRounding mode) {
if ((digits < 0) || (digits > maxRoundingDigits))
throw new ArgumentOutOfRangeException("digits", Environment.GetResourceString("ArgumentOutOfRange_RoundingDigits"));
if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) {
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumValue", mode, "MidpointRounding"), "mode");
}
return InternalRound(value, digits, mode);
}
public static Decimal Round(Decimal d) {
return Decimal.Round(d,0);
}
public static Decimal Round(Decimal d, int decimals) {
return Decimal.Round(d,decimals);
}
public static Decimal Round(Decimal d, MidpointRounding mode) {
return Decimal.Round(d, 0, mode);
}
public static Decimal Round(Decimal d, int decimals, MidpointRounding mode) {
return Decimal.Round(d, decimals, mode);
}
public static Decimal Floor(Decimal d) { return Decimal.Floor(d); }
[MethodImplAttribute(MethodImplOptions.InternalCall)] public static extern double Floor(double d);