후행 0 제거


177

컬렉션에서 일부 필드를 반환했습니다.

2.4200
2.0044
2.0000

나는 같은 결과를 원한다

2.42
2.0044
2

나는로 시도했지만 다른 값 을 반올림하도록 String.Format반환 2.0000하고 설정합니다 N0.


3
처음에는 레코드 유형이 문자열입니까?
Singleton

2
내 대답보기 : String.Format()'G'로 원하는 것을 얻을 수 있습니다. 표준 숫자 형식에 대한 링크로 답변을 업데이트했습니다. 매우 사용자 친화적입니다.
개 귀

3
10 진수는로 캐스트 될 수 있으며 double double의 기본값 ToString은 후행 0을 방출합니다. 이것을
Shimmy Weitzhandler

2
그리고 "G"를 문자열 형식으로 ToString함수에 전달하는 것보다 성능이 떨어질 것입니다 (매우 많은 레코드의 중간) .
Shimmy Weitzhandler

4
십진수를 이중으로 변환하면 의미가 없어지고 반올림이 부정확 할 수 있습니다.
kristianp

답변:


167

입력이 문자열이면 간단하지 않습니까? 다음 중 하나를 사용할 수 있습니다.

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

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

2.0m.ToString("G29")

이것은 모든 입력에서 작동합니다.

업데이트 문서가 명확하게 명시되어 있으므로 정밀도 지정자를 29로 명시 적으로 설정 해야하는 표준 숫자 형식을 확인하십시오 .

그러나 숫자가 10 진수이고 정밀도 지정자를 생략하면 고정 소수점 표기법이 항상 사용되며 후행 0이 유지됩니다.

Konrad 업데이트 는 의견에서 지적했습니다 .

0.000001과 같은 값을주의하십시오. G29 형식은 가장 짧은 방법으로 표시하므로 지수 표기법으로 전환됩니다. string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))결과적으로 "1E-08"이 표시됩니다.


1
모든 답변 중에서 가장 적은 단계가 필요했습니다. 개 귀 감사합니다.
Zo 님이

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

3
@Dave Hillier-알았습니다. 내 대답을 수정했습니다. 건배. [추가 명시 적으로 '정밀 지정자']
개 귀

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가 요구하는 것을 수행하기 때문에 소유합니다.
Coxy

2
0의 숫자는 정확한 양입니까, 아니면 가장 많이 예상되는 값입니까?
Simon_Weaver

3
MSDN은 "스케일링 팩터는 암시 적으로 숫자 10이며 0에서 28 사이의 지수로 올립니다"라고 말하며, 십진수는 소수점을 넘지 않은 최대 28 자리 숫자로 이해합니다. 0보다 크거나 같은 숫자는 28이어야합니다.
Thomas Materna

2
이것이 가장 좋은 대답입니다! 대답의 숫자는 34 숫자, 그 1뒤에 33 0-s가 있지만 decimal29 숫자, 1 1및 28 0-s 의 숫자와 정확히 동일한 인스턴스 를 만듭니다 . @ThomasMaterna가 그의 의견에서 말한 것처럼. System.Decimal숫자는 29자를 초과 할 수 없습니다 (앞자리가 큰 숫자는 총 28 자 보다 클 79228...수 있음 ). 더 많은 후행 0 을 원하면 나누지 말고 곱하십시오 . 또한 일부 0을 잘라낼 수 있습니다 (예 : gives) , 하나의 0 만 남습니다. 1.000...mMath.RoundMath.Round(27.40000m, 2)27.40m
Jeppe Stig Nielsen

2
훌륭한 트릭이지만 모노에서는 작동하지 않으며 .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

3
28 개의 '#'문자를 입력해야합니다 ( blackwasp.co.uk/DecimalTrailingZeroes.aspx 참조) .
Jaime Hablutzel 2016 년

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

1
최선의 방법. 다른 모든 것은 불필요하게 복잡합니다. 숫자에 소수점이 포함되어 있는지 항상 확인하십시오.
RRM

1
확장이되기 위해서는 매개 변수 앞에 "this"가 없습니다 : public static string DecimalToString (this decimal dec)
João Antunes

의견 감사합니다. 팁이 포함 된 새 버전으로 답변을 업데이트했습니다.
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
답이 아닙니다. 후행 0을 제거하지 않고 정밀도를 제거합니다. 후행 0이 없기 때문에 제안 된 방법 num1.ToString("0.##")13.1534545765(변경 없음)을 반환해야합니다 .
Jan 'splite'K.

이것이 바로 세 가지 제안 된 입력에 대한 답변을 표시하는 이유입니다. 따라서 사용자는 내 솔루션의 작동 방식을 확인할 수 있습니다.
Fizzix

제안 된 입력을 나열하더라도 질문에 대답하지 않습니다.
Dave Friedel

2
내가 할 수 있다면 ID를 10 번 공표했습니다. 정확히 내가 필요한 것!
SubqueryCrunch

1
질문에 대한 완벽한 답변. 내 의견으로는 최고의 답변입니다. 그것이 정밀도를 제거한다는 의견은 정확하지만 그 질문은 아닙니다. 가장 중요한 것은 내가 필요한 것입니다. 사용자는 일반적으로 2.5와 같은 정수를 입력하지만 소수점보다 세 자리를 지원해야합니다. 그래서 나는 그들이 입력하지 않은 많은 제로가 아닌 입력 한 것을주고 싶습니다. 예를 들어, 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
나는이 경로를 이동하려고했지만 정말 훨씬 더 빨리 당신보다 얻었다 그래서 예를 들어 분할하지 않음으로써, 그것을 더 최적화 한 하이중간 의 int를 (당신 ab그들 어쨌든 모두 0을 경우 반복하면서 모든에서). 그러나 나는 이 놀랍도록 간단한 솔루션을 발견 했는데, 이는 또한 당신과 내가 성능을 현명하게 만들어 낸 것을 쉽게 능가합니다 .
Eugene Beresovsky

2

이것은 작동합니다 :

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

또는 초기 값이 string다음과 같은 경우 :

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

이 의견에 주의 하십시오 .


2
@Damien, 예, 그리고이 목적에 대해 (십억 개의 레코드를 수행하지 않으면 아무것도 느끼지 않을 것입니다.) 첫 번째로 double이 빠르기 때문에 두 번째가 빠릅니다. 매개 변수를 전달합니다. 다시 한번 말하지만, 수많은 레코드 작업을하지 않으면 아무런 느낌이 없습니다.
Shimmy Weitzhandler

1
G를 지정할 필요가 없습니다. cuz double.ToString는 기본적으로 후행 0을 제거합니다.
Shimmy Weitzhandler

4
0.000001과 같은 값을주의하십시오. 이들은 지수 표기법으로 표시됩니다. double.Parse ( "0.00000001", System.Globalization.CultureInfo.GetCultureInfo ( "en-US")). ToString ()은 "1E-08"을 결과로 제공합니다
Konrad

17
절대 이러지 마 일반적으로 소수점이있는 이유는 숫자를 정확하게 표현하기 때문입니다 (거의 더블과 같지 않음). 물론,이 부동 소수점 오류는 아마도 매우 작지만, 잘못된 숫자를 표시 할 수 있습니다.
Adam Tegen

2
포맷을 위해 128 비트 데이터 유형 (10 진수)을 64 비트 데이터 유형 (더블)으로 변환하는 것은 좋은 생각이 아닙니다!
avl_sweden

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

십진수를 유지하려면 다음 예제를 시도하십시오.

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어떻습니까?
Stephen Drew

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

후행 0을 자르는 것은 매우 쉽습니다. 이중 캐스트로 해결하십시오.

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

(I)-> 모든 문자열 소스에서 10 진수 값을 구문 분석합니다.

(II)-> 먼저 : 두 배로 캐스트하면 후행 0이 제거됩니다. 둘째 : 소수에서 이중으로의 암시 적 변환이 존재하지 않기 때문에 다른 십진수로 변환


5
10 진수에 맞는 모든 값을 double에 맞추는 것으로 가정합니다. 오버플로 예외가 발생할 수 있습니다. 정밀도가 떨어질 수도 있습니다.
Martin Mulder

-2

이 코드를 사용해보십시오 :

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

왜 두 사람, 내 친구?
Raging Bull

2
'.'를 사용하지 않는 로케일은 어떻습니까?
Martin Mulder

이 게시물의 다른 접근법과 비교할 때 전혀 옵션이 아닙니다. 문자열과 뒷면에 변환하면 (때문에 로케일 적어도) 번호를 조작 할 수 항상 나쁜 옵션
블라디미르 Semashkin

-11

이렇게 해봐

string s = "2.4200";

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

그런 다음 부동으로 변환


1
당신은 subString()그것에 대한 방법을 사용할 수 있지만 여기에 게시 된 질문에 따르면, 나는 그런 요구 사항을 보지 못합니다 =)
Singleton

2
'.'를 사용하지 않는 로케일은 어떻습니까?
Dave Hillier

10
이것은 10.0의 배수 인 숫자에 대해 비참하게 실패합니다.
Ben Voigt

1
@BenVoigt가 말한 내용은 예를 들어로 끝날 것이므로 완전히 정확 "12300.00"합니다 "123". 바람직하지 않은 것처럼 보이는 또 다른 효과는 일부 숫자 "0.00"는 빈 문자열로 줄어드는 것입니다 ""(이 숫자 정수 "10.0"의 특수한 경우 임).
Jeppe Stig Nielsen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.