.NET には 1 つの組み込み関数があることは知っていますが、これは外部呼び出しです。誰でも理由を知っていますか?
しかし、実際の問題は、ユーザーが保持する桁数を指定できる切り捨てをゼロから実装する方法です。数値に 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.;
}
「理由」について: わかりませんが、Shared Source 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 が 10 進数値を保持する必要があると考える理由は明らかではありません。
.NET 内の既定のメソッドは、次のステートメントで記述されます。
d の整数部分。つまり、小数桁が破棄された後に残る数値です。
使用したいのは、double/decmial 値の出力文字列をフォーマットするか、代わりに Math.Round(double, int) 関数を使用することです。
あなたはただ使うことができます:
double num = 2.22939393; num = Convert.ToDouble(num.ToString("#0.000"));
重複した質問の1つから:
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
数値の 10 進値を保持するメソッドが必要でしたが、デフォルトの組み込みメソッドは保持していないため、このコードのみを提供しましTruncate
た。
あなたはいつもこれを使うことができます:
SplitFractionDouble
Math.Round は、私が言えることからを呼び出しません
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);