ASP.NET Decimal, Double 四捨五入

Decimal 带正负号十进位值是 Data Type 数据类型,用于表示精确的小数值。十进制 Decimal 非整数数值资料类型可以保存带正负号的 128 位元 (十六位元组) 16 Bits 值。Decimal 值适合用于财务计算或需要高精度的场合。需要大量数位但无法容许捨入错误的财务计算。

Decimal 十进位值

Decimal「带 ± 正负号」十进位值。
128 位固定点数数值型别。
小数点右边有 28 位数。( -7922816251426433759354395033579228162514264337593543950335 )

Dim DE As Decimal
DE.MaxValue = 79228162514264337593543950335 'Decimal 最大值
DE.MinValue = -79228162514264337593543950335 'Decimal 最小值
Dim DE As Decimal = 18.4555
Math.Round(DE) = 18
Math.Round(DE, 2) = 18.46
Math.Round(DE, 3) = 18.456
Math.Round(DE, MidpointRounding.ToEven) = 18
Math.Round(DE, 3, MidpointRounding.AwayFromZero) = 18.456


MidpointRounding 指定四捨五入的方式

MidpointRounding.AwayFromZero 而当数位在两个数字「中间点值」会四捨五入到最接近零的数位。
MidpointRounding.ToEven 当数位在两个数字「中间点值」会四捨五入到最接近的偶数。

分析 MidpointRounding.ToEven 四捨六入五取偶
银行家算法:四捨六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应捨去,五前为奇要进一。四捨六入五取偶是比较精确比较科学的数字修约方法,用于减少捨入误差的影响。这种方法在化学、统计等领域广泛使用,因为它可以使测量结果更接近真实值,而不是如 Rounding 四捨五入那样偏向大数或小数。

Math.Round(1.5, MidpointRounding.ToEven) '返回 2
Math.Round(2.5, MidpointRounding.ToEven) '返回 2
Math.Round(3.5, MidpointRounding.ToEven) '返回 4
Math.Round(4.5, MidpointRounding.ToEven) '返回 4
Math.Round(5.5, MidpointRounding.ToEven) '返回 6
Math.Round(6.5, MidpointRounding.ToEven) '返回 6

AwayFromZero 正数

Math.Round(1.4, MidpointRounding.AwayFromZero) '返回 1
Math.Round(1.5, MidpointRounding.AwayFromZero) '返回 2
Math.Round(1.6, MidpointRounding.AwayFromZero) '返回 2

AwayFromZero 负数

Math.Round(-1.4, MidpointRounding.AwayFromZero) '返回 -1
Math.Round(-1.5, MidpointRounding.AwayFromZero) '返回 -2
Math.Round(-1.6, MidpointRounding.AwayFromZero) '返回 -2


数值取捨的不同方式

Math.Round(DE) = 18 '进位值四捨五入到最接近的整数值
Math.Ceiling(DE) = 19 '返回「大于或等于」的最小整数值。
Math.Floor(DE) = 18 '返回「小于或等于」的最大整数值。
Math.Truncate(DE) = 18 '返回数字的「整数部分」

Double 双精度浮点数

Double「带 ± 正负号」双精度浮点数。
64 位浮点数数值型别。
-1.79769313486232E+3081.79769313486232E+308

DO.MaxValue = 1.79769313486232E+308 'Double 最大值
DO.MinValue = -1.79769313486232E+308 'Double 最小值
Dim DO As Decimal = 18.4555
Math.Round(DO) = 18
Math.Round(DO, 2) = 18.46
Math.Round(DO, 3) = 18.456
Math.Round(DO, MidpointRounding.ToEven) = 18
Math.Round(DO, 3, MidpointRounding.AwayFromZero) = 18.456
Math.Round(DO) = 18
Math.Ceiling(DO) = 19
Math.Floor(DO) = 18
Math.Truncate(DO) = 18

整理 ASPX 比较以上 Decimal, Double 数值看起来一样,但在官网上看到计算差异。

Decimal 类型计算结果

1 / 3 * 3 = 0.9999999999999999999999999999

Double, Single 类型计算结果

1 / 3 * 3 = 1

ASPX 相关 Decimal 数值处理

Dim DE As Decimal = Decimal.One '表示数字为 1
Dim DE As Decimal = Decimal.Zero '表示数字为 0
Dim DE As Decimal = Decimal.MinusOne '表示数字为 -1
Decimal.Multiply(Decimal, Decimal) 相乘方法。
Decimal.Divide(Decimal, Decimal) 相除方法。
Decimal.Remainder(Decimal, Decimal) 相除后的余数。
Decimal.Subtract(Decimal, Decimal) 相减方法。
Decimal.Negate(Decimal, Decimal) 变换「正负号」乘积的值。


ASP.NET, ASPX 相关 Math 数值格式处理

Math.IEEEremainder()

Math.IEEEremainder() 根据 IEEE 754 二进位浮点数算术标准,对「指定的 Number, Divisor 参数」执行除法运算返回余数。

Math.IEEEremainder(Number, Divisor)

返回 Number - (Base * Divisor),其中 Base 是最接近 Number / Divisor 的整数(四捨五入到最接近的整数值)。
而余数 Number Mod Divisor 返回 Number - (Base * Divisor),其中 Base 是 Number / Divisor 的「整数部分」。

Math.IEEEremainder(8, 3)
8 / 3 = 2.6666666666666665
Base = Math.Round(2.6666666666666665) = 3
8 - (3 * 3)
8 Mod 3 = 2
Base = Math.Truncate(2.6666666666666665) = 2
8 - (2 * 3)

尝试用 JavaScript 计算,但小数上有些差异。

let gNumber = 17.8
let gDivisor = 4
let gBase = Math.round(gNumber / gDivisor);
let IEEEremainder = gNumber - (gBase * gDivisor);

1.8000000000000007

Math.IEEEremainder(17.8, 4) '1.8

广泛为 CPU 与浮点运算器所採用使用的浮点数运算标准,我目前是没有机会使用到只是研究差异 😛。