首页 技术 正文
技术 2022年11月15日
0 收藏 918 点赞 4,895 浏览 4442 个字

在C#中如果float、double、decimal类型的值,小数点后的0太多时,C#会用科学记数法来表示小数的值。

例如下面的double类型0.00009,如果我们直接将其用ToString()方法转换为字符串,就会变为科学记数法9E-05

double number = 0.00009;
string defaultNumber = number.ToString(); //9E-05

此外如果float、double、decimal类型的值只有整数位,且整数后面有很多0,C#也会用科学记数法来表示整数的值,例如下面的double类型210000000000000000,如果我们直接将其用ToString()方法转换为字符串,就会变为科学记数法2.1E+17

double number = ;
string defaultNumber = number.ToString(); //2.1E+17

所以我们可以通过显式声明转换后字符串的格式,避免在C#中出现科学记数法:

using System;namespace NetCoreFloat
{
class Program
{
static void Main(string[] args)
{
double number = 0.00009;
string defaultNumber = number.ToString(); //9E-05 string numberFromToString = number.ToString("N5"); //0.00009 string numberFromStringFormat = string.Format("{0:F5}", number); //0.00009 Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

虽然上面的代码可以让小数转换为字符串后不是科学记数法,但是很明显我们需要准确地知道小数点后会有多少位小数,才能保证转换后的精度不会丢失。

如果我们将转换格式的精度设置得过小,就会造成精度损失,如下所示:

using System;namespace NetCoreFloat
{
class Program
{
static void Main(string[] args)
{
double number = 0.00009;
string defaultNumber = number.ToString(); //9E-05 string numberFromToString = number.ToString("N3"); //0.000 string numberFromStringFormat = string.Format("{0:F3}", number); //0.000 Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

而如果我们将转换格式的精度设置得过大,又会在小数最后产生多余的0,如下所示:

using System;namespace NetCoreFloat
{
class Program
{
static void Main(string[] args)
{
double number = 0.00009;
string defaultNumber = number.ToString(); //9E-05 string numberFromToString = number.ToString("N10"); //0.0000900000 string numberFromStringFormat = string.Format("{0:F10}", number); //0.0000900000 Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

对此我们需要在转换格式中使用#字符,#字符不会在小数最后产生多余的0,如下所示:

using System;namespace NetCoreFloat
{
class Program
{
static void Main(string[] args)
{
double number = 0.00009; string numberFromToString = number.ToString("0.#####"); //0.00009
numberFromToString = number.ToString("0.##########"); //0.00009 number = 100.00009;
numberFromToString = number.ToString("0.#####"); //100.00009
numberFromToString = number.ToString("0.##########"); //100.00009 number = ;
numberFromToString = number.ToString("0.#####"); //
numberFromToString = number.ToString("0.##########"); // Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

实际上我们可以最大声明339个#字符,这样可以保证所有小数都能被正确地转换为字符串:

using System;namespace NetCoreFloat
{
class Program
{
static void Main(string[] args)
{
double number = 0.00009; string numberFromToString = number.ToString("0." + new string('#', ));//0.00009 Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

我们也可以声明一个类FormatStrings,将339个#字符声明为一个字符串常量DoubleFixedPoint,这样用起来也会更方便:

using System;namespace NetCoreFloat
{
public static class FormatStrings
{
public const string DoubleFixedPoint = "0.###################################################################################################################################################################################################################################################################################################################################################";
} class Program
{
static void Main(string[] args)
{
double number = 0.00009; string numberFromToString = number.ToString(FormatStrings.DoubleFixedPoint);//0.00009 Console.WriteLine("Press any key to end...");
Console.ReadKey();
}
}
}

C#浮点数的精度问题

我们这里就拿double类型来举例,float和decimal类型以此类推, double的最大值是(double.MaxValue):

179769313486232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

其中有15位非0数字,也就是前面的179769313486232,那么它表示double类型可以存储整数位加小数位一共15位的有效数字(也就是说double类型中,第1位和最后1位非0的数字,一共能有15位)。

例如如果我们声明一个18位的小数number,然后通过ToString方法将其输出为字符串:

double number = 1234567890.12345678;//整数10位,小数8位
string numberFromToString = number.ToString("0." + new string('#', ));//1234567890.12346

可以看到ToString方法输出的是1234567890.12346,整数位加小数位一共只有15位,其中最后一位小数数字是6,是因为被#字符四舍五入了。

现在我们提高整数位的位数到13位,声明一个一共21位的小数,我们看看结果如何:

double number = 1234567890123.12345678;//整数13位,小数8位
string numberFromToString = number.ToString("0." + new string('#', ));//1234567890123.12

可以看到这次最后ToString方法输出的是1234567890123.12,整数位加小数位还是一共只有15位,而这次由于整数位占用了15位中的13位数字,所以小数位只剩下2位数字。

接下来我们声明一个一共20位的整数给double类型,看看结果如何:

double number = ;//整数20位
string numberFromToString = number.ToString("0." + new string('#', ));//

可以看到这次最后ToString方法输出的是12345678901231200000,原因就是因为double类型最大只能存储15位有效数字,所以最后5位1被截断了变为了0,只剩下了前面15位有效数字。

参考文献:

Converting numbers to strings without scientific notation in C#

Double to string conversion without scientific notation

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,985
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,501
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,345
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,128
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,763
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,840