删除尾随零


177

我有一些集合返回的字段

2.4200
2.0044
2.0000

我想要类似的结果

2.42
2.0044
2

我尝试使用String.Format,但是它返回2.0000并将其设置为也N0舍入其他值。


3
最初的记录类型是字符串?
辛格尔顿

2
看到我的答案:String.Format()用'G'应该可以得到您想要的。.我已经用标准数字格式的链接更新了我的答案。非常好用。
狗耳

3
可以将小数转换为double,而ToStringdouble 的默认值将尾随零。阅读此内容
Shimmy Weitzhandler,2010年

2
与将“ G”作为字符串格式传递给ToString函数相比,它可能会花费更少的性能(大量记录的间隔)。
Shimmy Weitzhandler,2010年

4
您不应该将小数转换为双精度数,它会失去重要性,并可能引入两个舍入不正确的功效。
kristianp 2015年

Answers:


166

如果输入是字符串,这不是那么简单吗?您可以使用以下之一:

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

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

2.0m.ToString("G29")

这应该适用于所有输入。

更新检查标准数字格式,我必须将docs明确指出的精度说明符设置为29:

但是,如果数字为小数并且省略了精度说明符,则始终使用定点表示法并保留尾随零。

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

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位的数字,有没有一种方法可以避免科学计数法?
吉尔,

202

我遇到了同样的问题,但是在我无法控制字符串输出的情况下,该问题由图书馆负责。在研究了Decimal类型的实现的详细信息之后(请参见http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx),我想到了一个巧妙的技巧(此处是扩展名)方法):

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

小数的指数部分减少到所需的大小。在输出的十进制上调用ToString()将写入数字而没有任何尾随的0。例如

1.200m.Normalize().ToString();

28
之所以拥有这个答案,是因为与这个问题(甚至整个主题)上的其他答案基本不同的是,它实际上是作品,并且可以执行OP的要求。
Coxy 2011年

2
0的数目在这里是确切的数量还是仅用于覆盖大多数期望值?
Simon_Weaver

3
MSDN指出“比例因子隐式为数字10,升至0到28之间的指数”,据我了解,十进制数字最多可以在小数点后28位。任何大于零或等于28的零都可以工作。
Thomas Materna

2
这是最好的答案!答案中的数字有34个数字,1后跟33个0-s,但这会创建decimal与29个数字(1个1和28个0-s)完全相同的实例。就像@ThomasMaterna在他的评论中所说。没有System.Decimal可以(与领先的数字大于数量已超过29倍的数字79228...只能有28的总数字)。如果您想要更多的尾随零,请乘以1.000...m而不是除。此外,Math.Round可以斩零一些零,例如Math.Round(27.40000m, 2)27.40m,所以只剩下一个零。
2013年

2
绝妙的技巧,但不适用于Mono,并且不能保证适用于.NET的功能版本
Bigjim 2013年


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
要成为一个扩展缺少“这”参数之前:公共静态字符串DecimalToString(此十进制DEC)
若昂·安图内斯

非常感谢您的评论。我已使用新版本的提示更新了答案。
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.

这就是为什么我要显示我的三个建议输入的答案的原因,以便用户可以看到我的解决方案的工作原理。
Fizzix

即使您列出建议的输入,它也不会回答问题。
戴夫·弗里德尔

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 ab)相除。但是,后来我发现了这个令人惊讶的简单解决方案,它也轻松击败了您和我提出的性能明智的解决方案
尤金·别列索夫斯基

2

这将起作用:

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

或者,如果您的初始值为string

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

请注意此评论


2
@Damien,是的,请注意,对于这些目的(除非做十亿条记录,否则您将不会有任何感觉),首先是因为double的速度更快,其次是因为将字符串格式传递给ToString函数比不使用它要花费更多的性能。传递参数。同样,除非您处理成千上万的记录,否则您将不会有任何感觉。
Shimmy Weitzhandler,2010年

1
您不必指定G,double.ToString默认情况下cuz 会删除尾随零。
Shimmy Weitzhandler,2010年

4
当心值,例如0.000001。这些将以指数符号表示。double.Parse(“ 0.00000001”,System.Globalization.CultureInfo.GetCultureInfo(“ en-US”))。ToString()的结果为“ 1E-08”
Konrad,

17
永远不要这样做。通常,使用小数的原因是因为您要精确地表示数字(近似不像双精度数)。当然,此浮点错误可能很小,但可能会显示不正确的数字,
尽管如此

2
糟糕,将128位数据类型(十进制)转换为64位数据类型(双精度)以进行格式化不是一个好主意!
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

如果要保留小数,请尝试以下示例:

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

截断尾随零非常简单,请使用双工强制转换:

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

(I)->从任何字符串源解析十进制值。

(II)->第一:强制转换为两倍以删除尾随零。第二:其他类型转换为十进制,因为不存在从十进制到双精度的隐式转换,反之亦然)


5
您假定所有的值都适合小数,适合双精度。这可能会导致OverflowExeception。您也可能会失去精度。
Martin Mulder 2014年

-2

试试这个代码:

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

为什么要回答两个,我的朋友?
愤怒的公牛

2
不使用'。'的语言环境呢?
Martin Mulder 2014年

与本文中的其他方法相比根本没有选择。转换为字符串然后返回总是操作数字的不好选择(至少是由于语言环境的影响)
Vladimir Semashkin

-11

这样尝试

string s = "2.4200";

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

然后将其转换为浮点


1
您可以使用该subString()方法,但是根据此处发布的问题,我没有看到类似的任何要求=)
Singleton 2010年

2
不使用'。'的语言环境呢?
Dave Hillier

10
对于10.0的偶数倍的数字,此操作将失败。
Ben Voigt

1
@BenVoigt所说的完全正确,因为一个例子"12300.00"将被精简为"123"。似乎不希望出现的另一个效果是,某些数字"0.00"会一直修剪到空字符串""(尽管此数字特殊的情况,是整数“ 10.0的倍数”)。
Jeppe Stig Nielsen 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.