当前位置: 首页 > 面试题库 >

为什么Firebird在除法时会截断小数位?

郭辉
2023-03-14
问题内容

Firebird在除法而不是舍入时会截断小数位。此外,它以分子和分母的小数位数为基础,将返回值的小数点位数作为基础。

为什么Firebird会被截断而不是四舍五入?为何将返回值基于查询中的小数位数?

Firebird2.5:

select 187/60.00 from rdb$database; --result: 3.11
select 187.000/60 from rdb$database; --result: 3.116
select 187.000/60.00 from rdb$database --result: 3.11666

SQL Server 2012:

select 187/60.00; --result: 3.116666

Oracle 11gR2:

select 187/60.00 from dual; --result: 3.116666666667

MySQL 5.5.32:

select 187/60.00 from dual; --result: 3.1167

PostgreSQL 9.3.1:

select 187/60.00; --result: 3.116666666667

SQLite:

select 187/60.00; --result: 3.1166666666666667

问题答案:

在Firebird中,带小数点的文字类型NUMERIC不是DOUBLE PRECISION(或其他浮点类型)。这意味着它将应用其确切的数值计算规则。

因此,select 187/60.00 from rdb$database这意味着187是an,INTEGER而60.00是a
NUMERIC(18,2)

精确数字计算的规则可以在“精确数字-功能说明”中找到:

如果两个操作数OP1和OP2分别是标度为S1和S2的精确数值,则OP1 +
OP2和OP1-OP2是精确度为18的精确数值,并标定S1和S2中的较大者,而OP1 * OP2和OP1 / OP2是精确数值精度为18,比例尺为S1
+
S2。(除除法运算外,这些操作的标度由SQL标准指定。该标准确定了所有这些运算的精度,除法的标度由实现定义:我们将精度定义为18,除法的标度定义为S1
+ S2,与乘法时标准所要求的相同。)

当操作数之一是整数类型时,它将被视为小数位数为0的数字。因此,在这种情况下,您具有,NUMERIC(18,0)/NUMERIC(18,2)并根据上述规则,结果为NUMERIC(18, 0+2) = NUMERIC(18,2)

该数字似乎被截断的事实是应用精确数字计算的结果:一旦计算出最后一位数字,计算就会停止。存在余数的事实与计算结果无关:

60.00 / 187 \ 3.11
        180
        ---
          70
          60
          --
          100
           60
           -- (stop)
           40

看一下SQL:2011 Foundation规范,Firebird认为60.00它是一个确切的数字是正确的,因为它在5.3
节中具有以下针对字面量的生产规则:

<literal> ::=
    <signed numeric literal>
  | <general literal>

<unsigned literal> ::=
    <unsigned numeric literal>
  | <general literal>

<signed numeric literal> ::=
    [ <sign> ] <unsigned numeric literal>

<unsigned numeric literal> ::=
    <exact numeric literal>
  | <approximate numeric literal>

<exact numeric literal> ::=
    <unsigned integer> [ <period> [ <unsigned integer> ] ]
  | <period> <unsigned integer>

<sign> ::=
    <plus sign>
  | <minus sign>

<approximate numeric literal> ::=
    <mantissa> E <exponent>

<mantissa> ::=
    <exact numeric literal>

<exponent> ::=
    <signed integer>

<signed integer> ::=
    [ <sign> ] <unsigned integer>

<unsigned integer> ::=
    <digit>...

和语法规则:

21)<exact numeric literal>没有a的<period>an表示<period>在last之后<digit>
22)<exact numeric literal>ENL的声明类型是实现定义的精确数字类型,其小数位数是<digit>右边的s数<period>。应该有一个能够精确表示ENL值的精确数字类型。

第6.27节<数值表达式>指定以下语法规则:

1)如果二进位算术运算符的两个操作数的声明类型均为精确数值,则结果的声明类型为实现定义的精确数值类型,其精度和小数位数确定如下:
a)令S1和S2为第一和第二操作数的小数位数。
b)加法和减法结果的精度是实现定义的,并且小数位数是S1和S2的最大值。
c)乘法结果的精度是实现定义的,小数位数是S1 + S2。
d) 除法结果的精度和小数位数由实现定义。

换句话说,Firebird的行为符合SQL标准。从外观上看,您尝试过的大多数其他数据库(SQL
Server可能例外)要么在执行除法时使用相对较大的比例值,要么似乎使用近似数值(也称为双精度)行为。

一种解决方法是使用近似数字文字。使用零或指数E0将使数字成为双精度,而没有额外的10的幂。例如:

select 187E0/60.00 from rdb$database; -- result: 3.116666666666667
-- or
select 187/60.00E0 from rdb$database; -- result: 3.116666666666667


 类似资料:
  • 我尝试在Jasper报告中格式化日期,它适用于Windows但不适用于Linux。对于Linux,结果文本被截断。 JRXML: Maven依赖关系: 我读到: 用jasperreport生成的PDF在Linux上显示不佳,但在Mac上显示良好,可能与os有关吗? http://community.jaspersoft.com/questions/527138/pdf-text-truncated

  • 问题内容: 我如何获得1324343032.324? 如您在下面看到的,以下内容不起作用: 问题答案: 如果要将其保存为,可以在其周围使用其他内容。

  • 问题内容: 我有一个长度为10 的类型的列: 在此列中,我插入了一个太长的数字: 当我查看表格中的内容时,数字现在是: 2147483647 变成了为什么,为什么? 为什么没有被截断? 这种转换背后的机制是什么,可以使用某些公式来计算结果数吗? 我不是在寻找解决方案。我只想了解具体数字。 问题答案: http://dev.mysql.com/doc/refman/5.0/en/integer- t

  • 问题内容: 我有一个包含4列的表格:ID,类型,所有者,描述。ID是AUTO_INCREMENT PRIMARY KEY,现在我要: 当然,我很少有类型=’Apple’和owner =’Apple CO’的记录。因此,我的问题是,哪条记录将是保留在该ALTER TABLE之后的特殊记录,ID最小的记录或最新插入的最大记录? 问题答案: 第一条记录将保留,其余的将被删除§§: 是标准SQL的MySQ

  • 我一直在监控我的应用程序错误,我看到下面的错误太多次了 错误:14077410:SSL例程:SSL23\u GET\u SERVER\u HELLO:sslv3警报握手失败(外部/openssl/SSL/s23\u clnt.c:741 0xaa48cd5c:0x00000000)-javax。网ssl。SSLHandshakeException:javax。网ssl。SSLProtocolExc

  • 大家好,我最近更新了我的库,升级了改版和OKHTTP。我正在使用的新版本包括以下导入/版本: 3)OkHttp日志记录-编译'com.squareup.okhttp3:logging-interceptor:3.4.1' 4)reverfit-编译“com.squareup.reverfit2:reverfit:2.1.0” 5)改造Gson转换器-编译'com.squareup.retrofit