程序开发中很多地方需要数值计算,有数值计算就有数值计算精度安全问题需要注关注。例如几何编辑、物理模拟、渲染着色计算等应用场景。常见的浮点数值计算精度问题会导致闪烁、裂缝等等瑕疵或错误。精度问题还会不停累计放大,如果计算规则不一致,加上开发者能力认知层次不齐,可能导致严重的错误。因此程序开发过程中应该提前将数值计算的精度控制统一起来,封装成符合项目需求的标准化操作。如下是TypeScript和c++两种语言的相关演示代码,用于交流探讨。
Typescript 演示代码:
/*******************************************************************************
* If the float number value is MATH_MAX_NEGATIVE < value < MATH_MIN_POSITIVE,
* the value can be considered ZERO, otherwise the value is not ZERO.
*******************************************************************************/
/**
* principle: x < MATH_MIN_POSITIVE, or x >= MATH_MIN_POSITIVE
*/
const MATH_MIN_POSITIVE = 1e-6;
/**
* principle: x <= MATH_MAX_NEGATIVE, or x > MATH_MAX_NEGATIVE
*/
const MATH_MAX_NEGATIVE = -1e-6;
function isZero(v: number) : boolean {
return v > MATH_MAX_NEGATIVE && v < MATH_MIN_POSITIVE;
}
function isNotZero(v: number) : boolean {
return v <= MATH_MAX_NEGATIVE || v >= MATH_MIN_POSITIVE;
}
/**
* example:
* isGreaterPositiveZero(0.1) is true
* isGreaterPositiveZero(0.000000001) is false
* isGreaterPositiveZero(-0.1) is false
* @param v number value
* @returns a positive number value and its value is greater zero, return true, otherwize false
*/
function isGreaterPositiveZero(v: number) : boolean {
return v >= MATH_MIN_POSITIVE;
}
/**
* example:
* isLessNegativeZero(-0.1) is true
* isLessNegativeZero(-000000001) is false
* isLessNegativeZero(0.1) is false
* @param v number value
* @returns a negative number value and its value is less zero, return true, otherwise false
*/
function isLessNegativeZero(v: number) : boolean {
return v <= MATH_MAX_NEGATIVE;
}
/**
* example:
* isLessPositiveZero(+0.00000001) is true
* isLessPositiveZero(-1.3) is true
* isLessPositiveZero(1.3) is false
* @param v number value
* @returns true or false
*/
function isLessPositiveZero(v: number) : boolean {
return v < MATH_MIN_POSITIVE;
}
/**
* example:
* isGreaterNegativeZero(-0.00000001) is true
* isGreaterNegativeZero(+1.3) is true
* isGreaterNegativeZero(-1.3) is false
* @param v number value
* @returns true or false
*/
function isGreaterNegativeZero(v: number) : boolean {
return v > MATH_MAX_NEGATIVE;
}
function isPostiveZero(v: number) : boolean {
return v >= 0.0 && v < MATH_MIN_POSITIVE;
}
function isNegativeZero(v: number) : boolean {
return v <= 0.0 && v > MATH_MAX_NEGATIVE;
}
function isGreaterRealZero(v: number) : boolean {
return v > 0.0;
}
function isLessRealZero(v: number) : boolean {
return v < 0.0;
}
C++演示代码:
/*******************************************************************************
* If the float number value is MATH_MAX_NEGATIVE < value < MATH_MIN_POSITIVE,
* the value can be considered ZERO, otherwise the value is not ZERO.
*******************************************************************************/
/**
* principle: x < MATH_MIN_POSITIVE, or x >= MATH_MIN_POSITIVE
*/
const double MATH_MIN_POSITIVE = 1e-6;
/**
* principle: x <= MATH_MAX_NEGATIVE, or x > MATH_MAX_NEGATIVE
*/
const double MATH_MAX_NEGATIVE = -1e-6;
inline bool isZero(double v) {
return v > MATH_MAX_NEGATIVE && v < MATH_MIN_POSITIVE;
}
inline bool isNotZero(double v) {
return v <= MATH_MAX_NEGATIVE || v >= MATH_MIN_POSITIVE;
}
/**
* example:
* isGreaterPositiveZero(0.1) is true
* isGreaterPositiveZero(0.000000001) is false
* isGreaterPositiveZero(-0.1) is false
* @param v number value
* @returns a positive number value and its value is greater zero, return true, otherwize false
*/
inline bool isGreaterPositiveZero(double v) {
return v >= MATH_MIN_POSITIVE;
}
/**
* example:
* isLessNegativeZero(-0.1) is true
* isLessNegativeZero(-0.000000001) is false
* isLessNegativeZero(0.1) is false
* @param v number value
* @returns a negative number value and its value is less zero, return true, otherwise false
*/
inline bool isLessNegativeZero(double v) {
return v <= MATH_MAX_NEGATIVE;
}
/**
* example:
* isLessPositiveZero(+0.00000001) is true
* isLessPositiveZero(-1.3) is true
* isLessPositiveZero(1.3) is false
* @param v number value
* @returns true or false
*/
inline bool isLessPositiveZero(double v) {
return v < MATH_MIN_POSITIVE;
}
/**
* example:
* isGreaterNegativeZero(-0.00000001) is true
* isGreaterNegativeZero(+1.3) is true
* isGreaterNegativeZero(-1.3) is false
* @param v number value
* @returns true or false
*/
inline bool isGreaterNegativeZero(double v) {
return v > MATH_MAX_NEGATIVE;
}
inline bool isPostiveZero(double v) {
return v >= 0.0 && v < MATH_MIN_POSITIVE;
}
inline bool isNegativeZero(double v) {
return v <= 0.0 && v > MATH_MAX_NEGATIVE;
}
inline bool isGreaterRealZero(double v) {
return v > 0.0;
}
inline bool isLessRealZero(double v) {
return v < 0.0;
}
以上示例代码用于对浮点函数的相关判断做了统一的封装,以便保证统一的计算效果。而不会因为一时的编码习惯而导致计算机制不一致。例如:
>MATH_MIN_POSITIVE 和 >= MATH_MIN_POSITIVE 就是不一样的。这种不同会导致结果差异而埋下难以提前察觉的错误。
当然,全面的数值精度管理,还要考虑软件功能设计目标需求的差异、运行环境的差异(或跨语言的实现)等等因素。总的来讲,能预先规避问题,总是更有价值的选择。