末尾のゼロを削除する


177

コレクションによって返されるいくつかのフィールドがあります

2.4200
2.0044
2.0000

次のような結果が欲しい

2.42
2.0044
2

で試しましたString.Formatが、戻り、他の値も丸める2.0000ように設定してN0います。


3
最初のレコードタイプは文字列ですか?
2010

2
私の回答を参照してください:String.Format()'G'を使用すると、必要なものが取得されます。標準の数値形式へのリンクで回答を更新しました。とても使いやすい。
Dog Ears 2010

3
小数はにキャストでき、double doubleのデフォルトToStringは後続ゼロを出力します。これをお
Shimmy Weitzhandler 2010

2
また、 "G"を文字列形式としてToString関数に渡すよりも、パフォーマンスが非常に低くなります(非常に大量のレコードの間隔)。
Shimmy Weitzhandler

4
10進数をdoubleに変換しないでください。重要度が失われ、2のべき乗の丸め誤差が発生する可能性があります。
kristianp 2015

回答:


167

入力が文字列の場合、これほど簡単ではありませんか?次のいずれかを使用できます。

string.Format("{0:G29}", decimal.Parse("2.0044"))

decimal.Parse("2.0044").ToString("G29")

2.0m.ToString("G29")

これはすべての入力で機能するはずです。

更新ドキュメントで明確に述べられているように、精度指定子を明示的に29に設定する必要があった標準の数値形式を確認してください。

ただし、数値がDecimalで精度指定子が省略されている場合、固定小数点表記が常に使用され、末尾のゼロは保持されます

Konrad がコメントで指摘し更新

0.000001などの値に注意してください。G29形式は、それらを可能な限り短い方法で表示するため、指数表記に切り替わります。string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))結果として「1E-08」が返されます。


1
すべての答えの中で、あなたの関与するステップは最も少なかった。犬耳ありがとうございます。
Zoは2010

4
var d = 2.0m; d.ToString( "G");
Dave Hillier、2011年

3
@Dave Hillier-なるほど、私は自分の答えを修正しました。乾杯。[明示的な「精度指定子」を追加]
Dog Ears

16
0.000001などの値に注意してください。G29形式は、それらを可能な限り短い方法で表示するため、指数表記に切り替わります。string.Format( "{0:G29}"、decimal.Parse( "0.00000001"、System.Globalization.CultureInfo.GetCultureInfo( "en-US")))は結果として "1E-08"を返します
Konrad

15
@Konrad-小数点以下5桁または6桁の数の科学表記を回避する方法はありますか?
Jill

202

私は同じ問題に遭遇しましたが、文字列への出力を制御できない場合、それはライブラリによって処理されました。Decimal型の実装の詳細を調べた後(http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspxを参照)、私はきちんとしたトリック(ここでは拡張機能として)を思い付きました方法):

public static decimal Normalize(this decimal value)
{
    return value/1.000000000000000000000000000000000m;
}

小数の指数部は、必要なものだけに削減されます。出力10進数でToString()を呼び出すと、末尾の0なしで数値が書き込まれます。

1.200m.Normalize().ToString();

29
基本的にこの質問の他のすべての回答とは異なり(そして件名全体も)実際には機能し、OPが求めていることを行うため、この回答は所有されます。
コクシー

2
ここで0の数は正確な数量ですか、それともほとんどの期待値をカバーするためですか?
Simon_Weaver

3
MSDNによると、「スケーリング係数は暗黙的に数値10であり、0から28の範囲の指数に引き上げられます」とあります。これは、10進数は小数点以下最大28桁になると理解しています。28以上の任意の数のゼロが機能するはずです。
Thomas Materna 2012年

2
これが一番の答えです!回答の数値は34桁で、1その後に33 0-sが続きdecimalますが、29桁の数値と1 1と28 0-sの数値とまったく同じインスタンスが作成されます。@ThomasMaternaがコメントで言ったように。System.Decimal29桁を超える79228...ことはできません(先頭の桁が大きい数字は合計で28桁しかありません)。より多くの後続ゼロが必要な場合は、除算では1.000...mなく乗算します。また、Math.Round例えば、いくつかのゼロを切り落とすことができますMath.Round(27.40000m, 2)与える27.40mので、唯一の1つのゼロを左に、。
Jeppe Stig Nielsen 2013

2
素晴らしいトリックですが、Monoでは機能せず、.NETの機能バージョンでの動作が保証されていません
Bigjim

87

私の意見では、カスタム数値フォーマット文字列を使用する方が安全です。

decimal d = 0.00000000000010000000000m;
string custom = d.ToString("0.#########################");
// gives: 0,0000000000001
string general = d.ToString("G29");
// gives: 1E-13

25
文書化された安定した動作に依存する唯一の回答の+1。
sinelaw、2014年

3
28文字の「#」文字をそこに配置する必要があります。blackwasp.co.uk/ DecimalTrailingZeroes.aspxを参照してください。
Jaime Hablutzel 2017年

32

このコードを使用して、「G29」の科学表記を回避します。

public static string DecimalToString(this decimal dec)
{
    string strdec = dec.ToString(CultureInfo.InvariantCulture);
    return strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec;
}

編集:システムCultureInfo.NumberFormat.NumberDecimalSeparatorを使用:

public static string DecimalToString(this decimal dec)
{
    string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    string strdec = dec.ToString(CultureInfo.CurrentCulture);
    return strdec.Contains(sep) ? strdec.TrimEnd('0').TrimEnd(sep.ToCharArray()) : strdec;
}

1
これは素晴らしい答えです。非常にシンプルで、マジックストリングフォーマッターを使用する代わりに、何が起こっているかを正確に確認できます。
ティモシーゴンザレス

9
いいですが、小数点記号にカンマを使用するカルチャでは機能しません。使用する必要がありますCulture.NumberFormat.NumberDecimalSeparator
blearyeye 2017年

1
最善のアプローチ。他のすべては不必要に複雑です。常に、数値に小数点が含まれているかどうかを確認することを忘れないでください。
RRM 2018年

1
公共の静的な文字列DecimalToString(この小数12月):拡張子は「この」パラメータの前に欠けているようにするには
ジョアン・アントゥネス

コメントありがとうございます。ヒントを含む新しいバージョンで回答を更新しました。
x7BiT

19

ハッシュ(#)記号を使用して、必要に応じて末尾の0のみを表示します。以下のテストを参照してください。

decimal num1 = 13.1534545765;
decimal num2 = 49.100145;
decimal num3 = 30.000235;

num1.ToString("0.##");       //13.15%
num2.ToString("0.##");       //49.1%
num3.ToString("0.##");       //30%

7
答えではありません。末尾のゼロを削除するのではなく、精度を削除します。後続のゼロがないため、提案されたメソッドnum1.ToString("0.##")13.1534545765(変更なしで)返す必要があります。
Jan 'splite' K.

そしてそれこそが、提案された3つの入力に対する回答を表示して、ユーザーが私のソリューションの動作を確認できるようにする理由です。
Fizzix

提案された入力をリストしても、質問には答えません。
Dave Friedel、2017

2
私はできればこれを10回賛成票で投票します。まさに私が必要とするもの!
SubqueryCrunch

1
質問に対する完璧な答え。私の意見では最良の答えです。それが精度を取り除くというコメントは正しいですが、それは問題ではありませんでした。最も重要なのは、それが私が必要としていることです。ユーザーは通常、2.5などの整数を入力しますが、小数点を超える3桁をサポートする必要があります。だから私は彼らが入力しなかったゼロの束ではなく、彼らが入力したものを彼らに与えたいです。例:Console.Write($ "num3 = {num3:0。##}"); => num3 = 30
bobwki


2

非常に低レベルのアプローチですが、これは高速整数計算のみを使用する(そして、遅い文字列解析やカルチャに依存したメソッドを使用しない)ことにより、最もパフォーマンスの高い方法になると思います。

public static decimal Normalize(this decimal d)
{
    int[] bits = decimal.GetBits(d);

    int sign = bits[3] & (1 << 31);
    int exp = (bits[3] >> 16) & 0x1f;

    uint a = (uint)bits[2]; // Top bits
    uint b = (uint)bits[1]; // Middle bits
    uint c = (uint)bits[0]; // Bottom bits

    while (exp > 0 && ((a % 5) * 6 + (b % 5) * 6 + c) % 10 == 0)
    {
        uint r;
        a = DivideBy10((uint)0, a, out r);
        b = DivideBy10(r, b, out r);
        c = DivideBy10(r, c, out r);
        exp--;
    }

    bits[0] = (int)c;
    bits[1] = (int)b;
    bits[2] = (int)a;
    bits[3] = (exp << 16) | sign;
    return new decimal(bits);
}

private static uint DivideBy10(uint highBits, uint lowBits, out uint remainder)
{
    ulong total = highBits;
    total <<= 32;
    total = total | (ulong)lowBits;

    remainder = (uint)(total % 10L);
    return (uint)(total / 10L);
}

1
私はこのルートに行こうとしましたが、さらに最適化しました。たとえば、すべてのwhile反復でhimidの整数(your aおよびb)を除算しないことで、それらがすべてゼロである場合は、それよりもはるかに高速になりました。しかし、私はこの驚くほど単純な解決策を見つけました。これは、あなたと私が優れたパフォーマンスを生み出したものを簡単に打ち負かします
Eugene Beresovsky、2015

2

これは動作します:

decimal source = 2.4200m;
string output = ((double)source).ToString();

または、初期値がstring次の場合:

string source = "2.4200";
string output = double.Parse(source).ToString();

このコメントに注意してください


2
@Damien、はい、そして注意してください。これらの目的(10億件のレコードを実行しない限り何も感じないでしょう)。最初はdoubleの方が速いため、2番目は、文字列形式をToString関数に渡すとパフォーマンスが低下するためです。パラメータを渡します。繰り返しになりますが、膨大な数のレコードを処理しない限り、何も感じません。
Shimmy Weitzhandler 2010

1
Gを指定する必要はありません。cuz double.ToStringはデフォルトで後続ゼロを削除します。
Shimmy Weitzhandler 2010

4
0.000001などの値に注意してください。これらは指数表記で表示されます。double.Parse( "0.00000001"、System.Globalization.CultureInfo.GetCultureInfo( "en-US"))。ToString()は結果として "1E-08"を返します
Konrad

17
これを行うことはありません。通常、10進数を使用する理由は、数値を正確に表現しているためです(doubleのようにではありません)。確かに、この浮動小数点エラーはおそらくかなり小さいですが、それでもなお、誤った数値を表示する可能性があります
Adam Tegen

2
書式設定のために128ビットのデータ型(10進数)を64ビットのデータ型(double)に変換することはお勧めできません。
avl_sweden 2014

2

これは簡単です。

decimal decNumber = Convert.ToDecimal(value);
        return decNumber.ToString("0.####");

テスト済み。

乾杯:)


1

数値が何を表しているか、および値をどのように管理するかによって異なります。それは通貨ですか、丸めまたは切り捨てが必要ですか、この丸めは表示のみに必要ですか?

表示用にフォーマットを検討する場合、数値はx.ToString( "")です。

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspxおよび

http://msdn.microsoft.com/en-us/library/0c899ak8.aspx

丸めだけの場合は、MidPointRoundingオーバーロードを必要とするMath.Roundオーバーロードを使用します。

http://msdn.microsoft.com/en-us/library/ms131274.aspx

データベースから値を取得する場合は、変換ではなくキャストを検討してください。double value =(decimal)myRecord ["columnName"];



0

10進数を保持する場合は、次の例を試してください。

number = Math.Floor(number * 100000000) / 100000000;

0

DecimalToStringのよりフレンドリーなソリューションを実行しようとしています(https://stackoverflow.com/a/34486763/3852139):

private static decimal Trim(this decimal value)
{
    var s = value.ToString(CultureInfo.InvariantCulture);
    return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
        ? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
        : value;
}

private static decimal? Trim(this decimal? value)
{
    return value.HasValue ? (decimal?) value.Value.Trim() : null;
}

private static void Main(string[] args)
{
    Console.WriteLine("=>{0}", 1.0000m.Trim());
    Console.WriteLine("=>{0}", 1.000000023000m.Trim());
    Console.WriteLine("=>{0}", ((decimal?) 1.000000023000m).Trim());
    Console.WriteLine("=>{0}", ((decimal?) null).Trim());
}

出力:

=>1
=>1.000000023
=>1.000000023
=>

-1

非常に簡単な答えは、TrimEnd()を使用することです。これが結果です

double value = 1.00;
string output = value.ToString().TrimEnd('0');

出力は1です。値が1.01の場合、出力は1.01になります。


4
場合はどうvalue = 100ですか?
スティーブンドリュー

4
@Raj De Inno値が1.00であっても、出力は「1」です。「1」ではない
Simba

-1

次のコードは、文字列型を使用しない場合に使用できます。

int decimalResult = 789.500
while (decimalResult>0 && decimalResult % 10 == 0)
{
    decimalResult = decimalResult / 10;
}
return decimalResult;

789.5を返します


-2

末尾のゼロの切り捨ては非常に簡単です。二重キャストで解決します。

        decimal mydecimal = decimal.Parse("1,45000000"); //(I)
        decimal truncate = (decimal)(double)mydecimal;   //(II)

(I)->任意の文字列ソースからの10進値を解析します。

(II)->最初に:これを2倍にキャストして、末尾のゼロを削除します。2番目:10進数から2進数への暗黙的な変換が存在しないため、その他は10進数にキャスト


5
10進数に収まるすべての値をdoubleに収まると想定します。これにより、OverflowExeceptionが発生する場合があります。また、精度が失われる場合があります。
Martin Mulder、

-2

このコードを試してください:

string value = "100";
value = value.Contains(".") ? value.TrimStart('0').TrimEnd('0').TrimEnd('.') : value.TrimStart('0');

なぜ2つの答え、私の友人?
レイジングブル

2
「。」を使用しないロケールについてはどうですか?
Martin Mulder

この投稿内の他のアプローチと比較して、オプションではありません。文字列への変換とその逆変換は、数値を操作するための常に悪いオプションです(少なくともロケールのため)
Vladimir Semashkin

-11

このようにしてみてください

string s = "2.4200";

s = s.TrimStart('0').TrimEnd('0', '.');

そしてそれを浮動小数点に変換します


1
subString()そのためのメソッドを使用できますが、ここに投稿された質問によると、そのような要件はありません=)
シングルトン

2
「。」を使用しないロケールについてはどうでしょうか。
Dave Hillier、2011年

10
これは、10.0の偶数倍である数値に対しては無残に失敗します。
Ben Voigt、2011

1
@BenVoigtの発言は、正解です。受験者"12300.00"はにトリミングされ"123"ます。望ましくないように見えるもう1つの影響は、などの一部の数値"0.00"が空の文字列にまで切り詰められることです""(ただし、この数値、整数の「10.0」の倍数である特別な場合です)。
Jeppe Stig Nielsen 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.