• 作者:老汪软件技巧
  • 发表时间:2024-09-24 07:02
  • 浏览量:

在我写完一段查询之后,代码一运行,发现从数据库中取出的百分比字段通过计算之后的结果竟然是0!

一个简单的乘除运算为什么会得到预料之外的结果呢?

那么开始我的探寻之路吧!

1. 寻找问题发生点

在出现这个问题的时候,首先我怀疑是数据库(代码环境使用的数据库是sqlserver)当中这个字段的值是0,导致结果为0,当我和往常一样打开数据库查询到这张表的时候,发现不对劲,数据库中的结果并不是0,存储的是一个整数60。

既然数据没有问题,现在就要开始从代码开始看起了。这段代码所需要计算的逻辑是从数据库中取出这一行的占比字段(percent),去和总量total相乘获取到这一行数据所占有的量,由于percent在数据库中存是的0-100的值,所以要先将percent转换为百分比再进行计算(即:percent / 100 * total)。

以运算符优先级的角度去看这行代码,除号和乘号的顺序应该不会对结果产生影响。但是我抱着死马当活马医的心理,去改变了一下计算逻辑,万一能成呢?现在的计算变成了percent * total / 100,理论上来说这两种计算应该是同样的结果才对。当我把改完的代码编译运行之后,不对劲,十分有十二分的不对劲。结果竟然正确了,当percent的值为60,total为5,结果竟然得出了正确的结果3(调换之前的结果是0),这个时候我想到乘除符号的顺序在这里肯定不会改变代码的结果才对,那么导致两次运算的结果不同的可能是:在第一次运算中,出现了精度丢失的情况!!!

2. 验证错误原因

既然问题出现的原因可能是精度丢失的问题,两个整型变量进行除法运算,那么数据库会不会将结果也转化成了int类型的结果呢?

想要验证这个结论的方法也很简单,将percent / 100 * total改为percent / 100.0 * total,理论上来说这样除法运算就会成为浮点数的运算,就不会将除法的结果转化成整型。此时在一次运行程序之后果然得到了正确的结果3。

3. 数据库?OR 编程语言?

既然确定了原因是精度问题导致的,那么究竟是数据库出现精度问题还是代码方面会出现这个问题呢?

3.1 数据库

由上面的问题,我验证了不同数据库对于SElECT 60/100*5的结果不同数据库在处理 SELECT 60/100*5 时的结果可能会有所不同,主要取决于它们如何处理整数除法和浮点数运算。以下是一些常见数据库的行为:

MySQL

在MySQL中,整数除法的结果会自动转换为浮点数。因此,SELECT 60/100*5 的结果是3.0。

PostgreSQL

在PostgreSQL中,整数除法的结果也是浮点数。因此,SELECT 60/100*5 的结果是3.0。

SQL Server

_数据库出现问题怎么办_数据库错误代码

在SQL Server中,整数除法的结果是整数。因此,SELECT 60/100*5 的结果是0。如果希望得到浮点数结果,可以将其中一个数转换为浮点数,例如 SELECT 60.0/100*5,结果是3.0。

Oracle

在Oracle中,整数除法的结果是整数。因此,SELECT 60/100*5 的结果是0。如果希望得到浮点数结果,可以将其中一个数转换为浮点数,例如 SELECT 60.0/100*5,结果是3.0。

SQLite

在SQLite中,整数除法的结果会自动转换为浮点数。因此,SELECT 60/100*5 的结果是3.0。

总结来说,不同数据库在处理整数除法时的行为可能会有所不同,特别是在是否自动转换为浮点数这一点上。如果我们希望确保得到浮点数结果,最好显式地将其中一个数转换为浮点数。

3.2 编程语言

在数据库层面对于不同的数据库会出现不同的结果,那么编程语言可能也会出现这样的情况,因此我简单的测试了一下。

不同编程语言在处理 60/100*5 时的结果可能会有所不同,主要取决于它们如何处理整数除法和浮点数运算。以下是一些主流编程语言的行为:

JavaScript

在JavaScript中,60/100的结果是0.6,这是一个浮点数。然后将0.6乘以5,结果是3.0。因此,console.log(60/100*5)的结果是3。

Java

在Java中,60/100的结果是0,因为整数除法会舍弃小数部分。然后将0乘以5,结果仍然是0。因此,System.out.println(60/100*5)的结果是0。如果希望得到浮点数结果,可以将其中一个数转换为浮点数,例如 60.0/100*5,结果是3.0。

Python

在Python中,60/100的结果是0,因为整数除法会舍弃小数部分。然后将0乘以5,结果仍然是0。因此,print(60/100*5)的结果是0。如果希望得到浮点数结果,可以使用浮点数除法,例如 60.0/100*5,结果是3.0。

C#

在C#中,60/100的结果是0,因为整数除法会舍弃小数部分。然后将0乘以5,结果仍然是0。因此,Console.WriteLine(60/100*5)的结果是0。如果希望得到浮点数结果,可以将其中一个数转换为浮点数,例如 60.0/100*5,结果是3.0。

C++

在C++中,60/100的结果是0,因为整数除法会舍弃小数部分。然后将0乘以5,结果仍然是0。因此,std::cout