|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
JavaScript作为一门动态类型语言,数字处理是日常开发中最常见的任务之一。无论是简单的算术运算、复杂的数学计算,还是数据格式化和精度控制,JavaScript都提供了丰富的API和方法。然而,由于JavaScript采用IEEE 754标准的双精度浮点数表示数字,开发者在处理数字时常常会遇到精度问题、范围限制和各种特殊情况的挑战。本指南将全面介绍JavaScript中的数字处理技术,从基础的数学运算到高级应用技巧,帮助你轻松掌握编程中的数字处理方法,提升开发效率,并解决实际项目中遇到的各种数字相关问题。
JavaScript中的数字基础
数字类型
在JavaScript中,所有数字都以64位双精度浮点数(double-precision floating-point format)表示,这是根据IEEE 754标准定义的。这意味着JavaScript没有像其他语言那样的整数类型,所有数字(无论整数还是小数)都属于number类型。
- let integer = 42; // 整数
- let float = 42.0; // 浮点数,但在JavaScript中与整数表示相同
- let negative = -42; // 负数
- let octal = 0o52; // 八进制表示法 (ES6)
- let hex = 0x2A; // 十六进制表示法
- let binary = 0b101010; // 二进制表示法 (ES6)
- console.log(typeof integer); // "number"
- console.log(typeof float); // "number"
- console.log(typeof negative); // "number"
复制代码
数字表示方法
JavaScript提供了多种表示数字的方法,包括十进制、二进制、八进制和十六进制:
- // 十进制(常规表示)
- let decimal = 255;
- // 二进制(以0b或0B开头)
- let binary = 0b11111111; // 等于十进制的255
- // 八进制(以0o或0O开头,ES6标准)
- let octal = 0o377; // 等于十进制的255
- // 十六进制(以0x或0X开头)
- let hex = 0xFF; // 等于十进制的255
- console.log(decimal === binary); // true
- console.log(decimal === octal); // true
- console.log(decimal === hex); // true
复制代码
特殊数字值
JavaScript中有几个特殊的数字值,了解它们对于正确处理数字运算非常重要:
- // Infinity - 表示正无穷大
- console.log(1 / 0); // Infinity
- console.log(Number.MAX_VALUE * 2); // Infinity
- // -Infinity - 表示负无穷大
- console.log(-1 / 0); // -Infinity
- console.log(-Number.MAX_VALUE * 2); // -Infinity
- // NaN - Not a Number,表示不是一个数字
- console.log(0 / 0); // NaN
- console.log(parseInt('abc')); // NaN
- // 检查NaN
- console.log(NaN === NaN); // false,NaN是唯一不等于自身的值
- console.log(isNaN(NaN)); // true,使用isNaN函数检查
- console.log(Number.isNaN(NaN)); // true,更严格的检查方式
- // 检查有限数字
- console.log(isFinite(100)); // true
- console.log(isFinite(Infinity)); // false
- console.log(isFinite(NaN)); // false
- // 最大和最小安全整数
- console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
- console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
- // 检查是否为安全整数
- console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
- console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
复制代码
基础数学运算
基本算术运算
JavaScript提供了基本的算术运算符,包括加(+)、减(-)、乘(*)、除(/)和取模(%):
- // 基本算术运算
- let a = 10;
- let b = 3;
- console.log(a + b); // 13 - 加法
- console.log(a - b); // 7 - 减法
- console.log(a * b); // 30 - 乘法
- console.log(a / b); // 3.3333333333333335 - 除法
- console.log(a % b); // 1 - 取模(余数)
- // 增量和减量
- let x = 5;
- x++; // 后增量,x变为6
- console.log(x); // 6
- ++x; // 前增量,x变为7
- console.log(x); // 7
- x--; // 后减量,x变为6
- console.log(x); // 6
- --x; // 前减量,x变为5
- console.log(x); // 5
- // 复合赋值运算符
- let y = 10;
- y += 5; // 等同于 y = y + 5,y变为15
- y -= 3; // 等同于 y = y - 3,y变为12
- y *= 2; // 等同于 y = y * 2,y变为24
- y /= 4; // 等同于 y = y / 4,y变为6
- y %= 4; // 等同于 y = y % 4,y变为2
复制代码
取整运算
在JavaScript中,有几种方法可以对数字进行取整:
- let num = 3.7;
- // Math.round() - 四舍五入
- console.log(Math.round(num)); // 4
- // Math.floor() - 向下取整
- console.log(Math.floor(num)); // 3
- // Math.ceil() - 向上取整
- console.log(Math.ceil(num)); // 4
- // Math.trunc() - 去除小数部分(ES6)
- console.log(Math.trunc(num)); // 3
- // 位运算取整(适用于32位整数)
- console.log(3.7 | 0); // 3
- console.log(~~3.7); // 3
- console.log(3.7 >> 0); // 3
- // 注意:负数时的区别
- let negativeNum = -3.7;
- console.log(Math.round(negativeNum)); // -4
- console.log(Math.floor(negativeNum)); // -4
- console.log(Math.ceil(negativeNum)); // -3
- console.log(Math.trunc(negativeNum)); // -3
复制代码
随机数生成
JavaScript的Math.random()函数可以生成0到1之间的随机数(不包括1),我们可以利用它来生成各种范围的随机数:
- // 生成0到1之间的随机数
- console.log(Math.random()); // 例如:0.123456789
- // 生成0到10之间的随机整数
- function getRandomInt(max) {
- return Math.floor(Math.random() * max);
- }
- console.log(getRandomInt(10)); // 0到9之间的整数
- // 生成指定范围内的随机整数
- function getRandomRange(min, max) {
- min = Math.ceil(min);
- max = Math.floor(max);
- return Math.floor(Math.random() * (max - min + 1)) + min;
- }
- console.log(getRandomRange(1, 10)); // 1到10之间的整数
- // 生成指定范围内的随机小数
- function getRandomFloat(min, max) {
- return Math.random() * (max - min) + min;
- }
- console.log(getRandomFloat(1.5, 3.5)); // 1.5到3.5之间的小数
- // 生成随机布尔值
- function getRandomBoolean() {
- return Math.random() < 0.5;
- }
- console.log(getRandomBoolean()); // true或false
- // 从数组中随机选择一个元素
- function getRandomItem(array) {
- return array[Math.floor(Math.random() * array.length)];
- }
- const colors = ['red', 'green', 'blue'];
- console.log(getRandomItem(colors)); // 随机返回一个颜色
复制代码
数字格式化
固定小数位数
在显示数字时,我们经常需要控制小数位数,可以使用toFixed()方法:
- let num = 3.14159265359;
- // 保留2位小数
- console.log(num.toFixed(2)); // "3.14"
- // 保留0位小数(四舍五入为整数)
- console.log(num.toFixed(0)); // "3"
- // 注意:toFixed返回的是字符串,不是数字
- console.log(typeof num.toFixed(2)); // "string"
- // 如果需要数字类型,需要转换
- let formattedNum = parseFloat(num.toFixed(2));
- console.log(typeof formattedNum); // "number"
- // 处理不足小数位数的情况
- let shortNum = 5;
- console.log(shortNum.toFixed(3)); // "5.000" - 自动补零
复制代码
科学计数法
对于非常大或非常小的数字,可以使用toExponential()方法将其转换为科学计数法表示:
- let bigNum = 123456789;
- let smallNum = 0.000012345;
- // 转换为科学计数法
- console.log(bigNum.toExponential()); // "1.23456789e+8"
- console.log(smallNum.toExponential()); // "1.2345e-5"
- // 指定小数位数
- console.log(bigNum.toExponential(2)); // "1.23e+8"
- console.log(smallNum.toExponential(3)); // "1.235e-5"
- // toExponential也返回字符串
- console.log(typeof bigNum.toExponential()); // "string"
复制代码
数字分隔符
为了提高大数字的可读性,ES2021引入了数字分隔符(_):
- // 使用数字分隔符提高可读性
- let billion = 1_000_000_000;
- let bytes = 0b1111_1111_1111_1111;
- let hex = 0xFF_FF_FF_FF;
- console.log(billion); // 1000000000
- console.log(bytes); // 65535
- console.log(hex); // 4294967295
- // 分隔符可以放在数字之间的任何位置,但不能放在开头、结尾或小数点旁边
- let valid = 1_2_3.4_5; // 有效
- let invalid = _123; // 无效
- let alsoInvalid = 123_; // 无效
- let alsoAlsoInvalid = 123._45; // 无效
复制代码
货币格式化
在处理货币时,我们需要精确的格式化,可以使用Intl.NumberFormat对象:
- // 基本货币格式化
- let amount = 123456.789;
- // 美元格式
- let usdFormatter = new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency: 'USD'
- });
- console.log(usdFormatter.format(amount)); // "$123,456.79"
- // 欧元格式
- let eurFormatter = new Intl.NumberFormat('de-DE', {
- style: 'currency',
- currency: 'EUR'
- });
- console.log(eurFormatter.format(amount)); // "123.456,79 €"
- // 人民币格式
- let cnyFormatter = new Intl.NumberFormat('zh-CN', {
- style: 'currency',
- currency: 'CNY'
- });
- console.log(cnyFormatter.format(amount)); // "¥123,456.79"
- // 不使用货币符号,只格式化数字
- let numberFormatter = new Intl.NumberFormat('en-US');
- console.log(numberFormatter.format(amount)); // "123,456.789"
- // 指定最小和最大小数位数
- let preciseFormatter = new Intl.NumberFormat('en-US', {
- minimumFractionDigits: 2,
- maximumFractionDigits: 2
- });
- console.log(preciseFormatter.format(amount)); // "123,456.79"
复制代码
高级数字处理
大整数(BigInt)处理
JavaScript的number类型只能安全表示-2^53到2^53之间的整数(即-9007199254740992到9007199254740992)。对于超出这个范围的整数,ES2020引入了BigInt类型:
- // 创建BigInt - 在数字后加n或使用BigInt()构造函数
- let bigInt1 = 9007199254740993n; // 超出安全整数范围
- let bigInt2 = BigInt(9007199254740993);
- console.log(typeof bigInt1); // "bigint"
- console.log(bigInt1 === bigInt2); // true
- // BigInt运算
- console.log(100n + 50n); // 150n
- console.log(100n - 50n); // 50n
- console.log(100n * 50n); // 5000n
- console.log(100n / 50n); // 2n (注意:BigInt除法会向下取整)
- console.log(100n % 50n); // 0n
- // 比较运算
- console.log(10n > 5n); // true
- console.log(10n < 5n); // false
- console.log(10n === 10); // false (BigInt和number类型不同)
- console.log(10n == 10); // true (宽松相等)
- // 位运算
- console.log(5n | 3n); // 7n
- console.log(5n & 3n); // 1n
- console.log(5n ^ 3n); // 6n
- console.log(~5n); // -6n
- // BigInt与普通数字的混合运算会抛出错误
- try {
- console.log(10n + 5); // TypeError: Cannot mix BigInt and other types
- } catch (e) {
- console.error(e.message);
- }
- // 需要显式转换
- console.log(10n + BigInt(5)); // 15n
- console.log(Number(10n) + 5); // 15
- // 实际应用:计算大数阶乘
- function factorial(n) {
- if (n === 0n) return 1n;
- return n * factorial(n - 1n);
- }
- console.log(factorial(20n)); // 2432902008176640000n
- // 使用普通number计算20的阶乘会得到不准确的结果
- console.log(factorial(20)); // 2432902008176640000 (但超过20会不准确)
复制代码
精确计算(避免浮点数精度问题)
JavaScript使用二进制浮点数表示十进制数字,这会导致一些精度问题,例如:
- // 浮点数精度问题示例
- console.log(0.1 + 0.2); // 0.30000000000000004
- console.log(0.3 - 0.1); // 0.19999999999999998
- console.log(0.1 * 0.2); // 0.020000000000000004
- console.log(0.3 / 0.1); // 2.9999999999999996
复制代码
解决这些精度问题的方法有多种:
- function add(a, b) {
- return parseFloat((a + b).toFixed(10));
- }
- console.log(add(0.1, 0.2)); // 0.3
复制代码- function preciseAdd(a, b, precision = 10) {
- const factor = Math.pow(10, precision);
- return (Math.round(a * factor) + Math.round(b * factor)) / factor;
- }
- console.log(preciseAdd(0.1, 0.2)); // 0.3
- console.log(preciseAdd(0.15, 0.25)); // 0.4
复制代码- // 假设已经引入了decimal.js库
- // <script src="https://cdn.jsdelivr.net/npm/decimal.js@10.4.3/decimal.min.js"></script>
- // 使用decimal.js进行精确计算
- const Decimal = Decimal; // 在实际环境中,这应该是全局可用的
- let a = new Decimal(0.1);
- let b = new Decimal(0.2);
- console.log(a.plus(b).toString()); // "0.3"
- let c = new Decimal(0.15);
- let d = new Decimal(0.25);
- console.log(c.plus(d).toString()); // "0.4"
复制代码- // 使用BigInt进行精确的小数计算
- function preciseDecimalAdd(a, b, precision = 10) {
- const factor = BigInt(Math.pow(10, precision));
- const aInt = BigInt(Math.round(a * Math.pow(10, precision)));
- const bInt = BigInt(Math.round(b * Math.pow(10, precision)));
- const result = aInt + bInt;
- return Number(result) / Number(factor);
- }
- console.log(preciseDecimalAdd(0.1, 0.2)); // 0.3
- console.log(preciseDecimalAdd(0.15, 0.25)); // 0.4
复制代码
数字转换和解析
在JavaScript中,有几种方法可以将字符串转换为数字,或者将数字转换为字符串:
- // 字符串转数字
- let strNum1 = "123";
- let strNum2 = "123.45";
- let strNum3 = "123abc";
- let strNum4 = "abc123";
- // 使用Number()构造函数
- console.log(Number(strNum1)); // 123
- console.log(Number(strNum2)); // 123.45
- console.log(Number(strNum3)); // NaN
- console.log(Number(strNum4)); // NaN
- // 使用parseInt() - 解析整数
- console.log(parseInt(strNum1)); // 123
- console.log(parseInt(strNum2)); // 123
- console.log(parseInt(strNum3)); // 123
- console.log(parseInt(strNum4)); // NaN
- // 使用parseFloat() - 解析浮点数
- console.log(parseFloat(strNum1)); // 123
- console.log(parseFloat(strNum2)); // 123.45
- console.log(parseFloat(strNum3)); // 123
- console.log(parseFloat(strNum4)); // NaN
- // 使用一元加号运算符
- console.log(+strNum1); // 123
- console.log(+strNum2); // 123.45
- console.log(+strNum3); // NaN
- console.log(+strNum4); // NaN
- // 数字转字符串
- let num1 = 123;
- let num2 = 123.45;
- // 使用String()函数
- console.log(String(num1)); // "123"
- console.log(String(num2)); // "123.45"
- // 使用toString()方法
- console.log(num1.toString()); // "123"
- console.log(num2.toString()); // "123.45"
- // 使用模板字符串
- console.log(`${num1}`); // "123"
- console.log(`${num2}`); // "123.45"
- // 使用空字符串连接
- console.log(num1 + ""); // "123"
- console.log(num2 + ""); // "123.45"
- // 指定进制转换
- let hexNum = 255;
- console.log(hexNum.toString(16)); // "ff"
- console.log(hexNum.toString(8)); // "377"
- console.log(hexNum.toString(2)); // "11111111"
- // 从不同进制解析
- console.log(parseInt("ff", 16)); // 255
- console.log(parseInt("377", 8)); // 255
- console.log(parseInt("11111111", 2)); // 255
复制代码
实用数字技巧
数字范围限制
在实际开发中,我们经常需要将数字限制在特定范围内:
- // 使用Math.min()和Math.max()限制范围
- function clamp(value, min, max) {
- return Math.min(Math.max(value, min), max);
- }
- console.log(clamp(10, 0, 100)); // 10
- console.log(clamp(-10, 0, 100)); // 0
- console.log(clamp(110, 0, 100)); // 100
- // 循环范围(超出范围后从另一端继续)
- function wrap(value, min, max) {
- const range = max - min;
- return ((value - min) % range + range) % range + min;
- }
- console.log(wrap(5, 0, 10)); // 5
- console.log(wrap(15, 0, 10)); // 5
- console.log(wrap(-5, 0, 10)); // 5
- // 将数字映射到不同范围
- function map(value, fromMin, fromMax, toMin, toMax) {
- return (value - fromMin) * (toMax - toMin) / (fromMax - fromMin) + toMin;
- }
- console.log(map(5, 0, 10, 0, 100)); // 50
- console.log(map(2, 0, 10, 0, 100)); // 20
- console.log(map(8, 0, 10, 0, 100)); // 80
- // 线性插值
- function lerp(start, end, t) {
- return start * (1 - t) + end * t;
- }
- console.log(lerp(0, 100, 0.5)); // 50
- console.log(lerp(0, 100, 0.25)); // 25
- console.log(lerp(0, 100, 0.75)); // 75
复制代码
数字验证
验证用户输入或处理数据时,我们需要确保数字的有效性:
- // 检查是否为有效数字
- function isValidNumber(value) {
- return typeof value === 'number' && !isNaN(value) && isFinite(value);
- }
- console.log(isValidNumber(123)); // true
- console.log(isValidNumber(123.45)); // true
- console.log(isValidNumber(NaN)); // false
- console.log(isValidNumber(Infinity)); // false
- console.log(isValidNumber("123")); // false
- console.log(isValidNumber(null)); // false
- // 检查是否为整数
- function isInteger(value) {
- return typeof value === 'number' && !isNaN(value) && isFinite(value) && value % 1 === 0;
- }
- console.log(isInteger(123)); // true
- console.log(isInteger(123.0)); // true
- console.log(isInteger(123.45)); // false
- console.log(isInteger("123")); // false
- // 检查是否为安全整数
- function isSafeInteger(value) {
- return typeof value === 'number' && !isNaN(value) && isFinite(value) &&
- value % 1 === 0 && value >= Number.MIN_SAFE_INTEGER &&
- value <= Number.MAX_SAFE_INTEGER;
- }
- console.log(isSafeInteger(123)); // true
- console.log(isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
- console.log(isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
- console.log(isSafeInteger(9007199254740993)); // false
- // 检查是否为数字字符串
- function isNumericString(value) {
- return typeof value === 'string' && !isNaN(value) && value.trim() !== '';
- }
- console.log(isNumericString("123")); // true
- console.log(isNumericString("123.45")); // true
- console.log(isNumericString("123abc")); // false
- console.log(isNumericString("abc123")); // false
- console.log(isNumericString("")); // false
- console.log(isNumericString(" ")); // false
- // 检查数字是否在指定范围内
- function isInRange(value, min, max) {
- return isValidNumber(value) && value >= min && value <= max;
- }
- console.log(isInRange(50, 0, 100)); // true
- console.log(isInRange(-10, 0, 100)); // false
- console.log(isInRange(110, 0, 100)); // false
- console.log(isInRange("50", 0, 100)); // false
复制代码
数字性能优化
在处理大量数字计算时,性能优化变得尤为重要:
实际应用场景
数据可视化中的数字处理
在数据可视化中,数字处理是必不可少的,例如缩放、格式化和转换:
- // 数据缩放 - 将数据映射到可视化区域
- class DataScaler {
- constructor(dataMin, dataMax, viewMin, viewMax) {
- this.dataMin = dataMin;
- this.dataMax = dataMax;
- this.viewMin = viewMin;
- this.viewMax = viewMax;
- }
-
- // 数据值转换为视图坐标
- dataToView(dataValue) {
- const dataRange = this.dataMax - this.dataMin;
- const viewRange = this.viewMax - this.viewMin;
- return ((dataValue - this.dataMin) / dataRange) * viewRange + this.viewMin;
- }
-
- // 视图坐标转换为数据值
- viewToData(viewValue) {
- const dataRange = this.dataMax - this.dataMin;
- const viewRange = this.viewMax - this.viewMin;
- return ((viewValue - this.viewMin) / viewRange) * dataRange + this.dataMin;
- }
- }
- // 使用示例:将温度数据(0-40°C)映射到图表高度(0-500px)
- const tempScaler = new DataScaler(0, 40, 500, 0); // 注意:Y轴通常是从上到下增长的
- console.log(tempScaler.dataToView(20)); // 250 (中间位置)
- console.log(tempScaler.dataToView(30)); // 125 (四分之一位置)
- console.log(tempScaler.viewToData(250)); // 20°C
- console.log(tempScaler.viewToData(125)); // 30°C
- // 自动计算刻度
- function calculateTicks(min, max, maxTicks = 10) {
- const range = max - min;
- const roughStep = range / (maxTicks - 1);
-
- // 计算合适的步长(1, 2, 5, 10, 20, 50, 100等)
- const exponent = Math.floor(Math.log10(roughStep));
- const fraction = roughStep / Math.pow(10, exponent);
- let niceFraction;
-
- if (fraction < 1.5) {
- niceFraction = 1;
- } else if (fraction < 3) {
- niceFraction = 2;
- } else if (fraction < 7) {
- niceFraction = 5;
- } else {
- niceFraction = 10;
- }
-
- const step = niceFraction * Math.pow(10, exponent);
- const niceMin = Math.floor(min / step) * step;
- const niceMax = Math.ceil(max / step) * step;
-
- const ticks = [];
- for (let tick = niceMin; tick <= niceMax; tick += step) {
- ticks.push(tick);
- }
-
- return {
- min: niceMin,
- max: niceMax,
- step: step,
- ticks: ticks
- };
- }
- // 使用示例:为数据范围[3.7, 48.3]计算合适的刻度
- const ticks = calculateTicks(3.7, 48.3);
- console.log(ticks);
- // 输出:
- // {
- // min: 0,
- // max: 50,
- // step: 10,
- // ticks: [0, 10, 20, 30, 40, 50]
- // }
- // 数字格式化 - 根据数值大小自动选择单位
- function formatNumber(value) {
- const abs = Math.abs(value);
-
- if (abs >= 1000000000) {
- return (value / 1000000000).toFixed(1) + 'B'; // 十亿
- } else if (abs >= 1000000) {
- return (value / 1000000).toFixed(1) + 'M'; // 百万
- } else if (abs >= 1000) {
- return (value / 1000).toFixed(1) + 'K'; // 千
- } else {
- return value.toString();
- }
- }
- console.log(formatNumber(1234)); // "1.2K"
- console.log(formatNumber(1234567)); // "1.2M"
- console.log(formatNumber(1234567890)); // "1.2B"
- console.log(formatNumber(-567)); // "-567"
复制代码
游戏开发中的数字计算
游戏开发中经常需要处理各种数字计算,包括物理模拟、动画和随机事件:
- // 向量运算(2D)
- class Vector2 {
- constructor(x = 0, y = 0) {
- this.x = x;
- this.y = y;
- }
-
- // 向量加法
- add(vector) {
- return new Vector2(this.x + vector.x, this.y + vector.y);
- }
-
- // 向量减法
- subtract(vector) {
- return new Vector2(this.x - vector.x, this.y - vector.y);
- }
-
- // 标量乘法
- multiply(scalar) {
- return new Vector2(this.x * scalar, this.y * scalar);
- }
-
- // 向量点积
- dot(vector) {
- return this.x * vector.x + this.y * vector.y;
- }
-
- // 向量长度
- length() {
- return Math.sqrt(this.x * this.x + this.y * this.y);
- }
-
- // 向量归一化
- normalize() {
- const len = this.length();
- if (len > 0) {
- return new Vector2(this.x / len, this.y / len);
- }
- return new Vector2(0, 0);
- }
-
- // 旋转向量
- rotate(angle) {
- const cos = Math.cos(angle);
- const sin = Math.sin(angle);
- return new Vector2(
- this.x * cos - this.y * sin,
- this.x * sin + this.y * cos
- );
- }
- }
- // 使用示例
- const v1 = new Vector2(3, 4);
- const v2 = new Vector2(1, 2);
- console.log(v1.add(v2)); // Vector2 { x: 4, y: 6 }
- console.log(v1.length()); // 5
- console.log(v1.normalize()); // Vector2 { x: 0.6, y: 0.8 }
- // 缓动函数 - 用于平滑动画
- const Easing = {
- linear: (t) => t,
-
- easeInQuad: (t) => t * t,
- easeOutQuad: (t) => t * (2 - t),
- easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
-
- easeInCubic: (t) => t * t * t,
- easeOutCubic: (t) => (--t) * t * t + 1,
- easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
-
- easeInElastic: (t) => {
- if (t === 0 || t === 1) return t;
- const p = 0.3;
- return -Math.pow(2, 10 * (t - 1)) * Math.sin((t - 1.1) * 5 * Math.PI / p);
- },
- easeOutElastic: (t) => {
- if (t === 0 || t === 1) return t;
- const p = 0.3;
- return Math.pow(2, -10 * t) * Math.sin((t - 0.1) * 5 * Math.PI / p) + 1;
- }
- };
- // 使用缓动函数进行动画
- function animateValue(start, end, duration, easingFunction = Easing.linear, callback) {
- const startTime = performance.now();
-
- function update(currentTime) {
- const elapsed = currentTime - startTime;
- const progress = Math.min(elapsed / duration, 1);
- const easedProgress = easingFunction(progress);
- const currentValue = start + (end - start) * easedProgress;
-
- callback(currentValue);
-
- if (progress < 1) {
- requestAnimationFrame(update);
- }
- }
-
- requestAnimationFrame(update);
- }
- // 使用示例:在2秒内将值从0动画到100,使用easeOutCubic缓动
- animateValue(0, 100, 2000, Easing.easeOutCubic, (value) => {
- console.log(value.toFixed(2));
- });
- // 概率系统 - 用于游戏中的随机事件
- class ProbabilitySystem {
- constructor() {
- this.events = [];
- }
-
- // 添加事件及其概率
- addEvent(event, probability) {
- this.events.push({ event, probability });
- return this;
- }
-
- // 随机选择一个事件
- random() {
- const totalProbability = this.events.reduce((sum, e) => sum + e.probability, 0);
- let random = Math.random() * totalProbability;
-
- for (const event of this.events) {
- random -= event.probability;
- if (random <= 0) {
- return event.event;
- }
- }
-
- return this.events[this.events.length - 1].event;
- }
- }
- // 使用示例:创建一个战利品掉落系统
- const lootSystem = new ProbabilitySystem()
- .addEvent("普通装备", 60)
- .addEvent("稀有装备", 30)
- .addEvent("史诗装备", 9)
- .addEvent("传说装备", 1);
- // 模拟100次掉落
- const lootCounts = { "普通装备": 0, "稀有装备": 0, "史诗装备": 0, "传说装备": 0 };
- for (let i = 0; i < 100; i++) {
- const loot = lootSystem.random();
- lootCounts[loot]++;
- }
- console.log(lootCounts);
- // 输出类似于: { "普通装备": 58, "稀有装备": 32, "史诗装备": 8, "传说装备": 2 }
复制代码
金融计算中的精确数字处理
金融计算对数字精度要求极高,JavaScript的浮点数精度问题可能会导致严重错误:
- // 金融计算工具类
- class FinancialCalculator {
- // 精确的加法
- static add(a, b) {
- const aStr = a.toString();
- const bStr = b.toString();
-
- // 找出小数点后的最大位数
- const aDecimalPlaces = aStr.includes('.') ? aStr.split('.')[1].length : 0;
- const bDecimalPlaces = bStr.includes('.') ? bStr.split('.')[1].length : 0;
- const maxDecimalPlaces = Math.max(aDecimalPlaces, bDecimalPlaces);
-
- // 转换为整数进行计算
- const factor = Math.pow(10, maxDecimalPlaces);
- const aInt = Math.round(a * factor);
- const bInt = Math.round(b * factor);
-
- return (aInt + bInt) / factor;
- }
-
- // 精确的减法
- static subtract(a, b) {
- const aStr = a.toString();
- const bStr = b.toString();
-
- // 找出小数点后的最大位数
- const aDecimalPlaces = aStr.includes('.') ? aStr.split('.')[1].length : 0;
- const bDecimalPlaces = bStr.includes('.') ? bStr.split('.')[1].length : 0;
- const maxDecimalPlaces = Math.max(aDecimalPlaces, bDecimalPlaces);
-
- // 转换为整数进行计算
- const factor = Math.pow(10, maxDecimalPlaces);
- const aInt = Math.round(a * factor);
- const bInt = Math.round(b * factor);
-
- return (aInt - bInt) / factor;
- }
-
- // 精确的乘法
- static multiply(a, b) {
- const aStr = a.toString();
- const bStr = b.toString();
-
- // 计算小数点后的总位数
- const aDecimalPlaces = aStr.includes('.') ? aStr.split('.')[1].length : 0;
- const bDecimalPlaces = bStr.includes('.') ? bStr.split('.')[1].length : 0;
- const totalDecimalPlaces = aDecimalPlaces + bDecimalPlaces;
-
- // 转换为整数进行计算
- const aInt = Math.round(a * Math.pow(10, aDecimalPlaces));
- const bInt = Math.round(b * Math.pow(10, bDecimalPlaces));
-
- return (aInt * bInt) / Math.pow(10, totalDecimalPlaces);
- }
-
- // 精确的除法
- static divide(a, b, precision = 10) {
- if (b === 0) throw new Error("Division by zero");
-
- const aStr = a.toString();
- const bStr = b.toString();
-
- // 计算小数点后的位数
- const aDecimalPlaces = aStr.includes('.') ? aStr.split('.')[1].length : 0;
- const bDecimalPlaces = bStr.includes('.') ? bStr.split('.')[1].length : 0;
-
- // 转换为整数进行计算
- const aInt = Math.round(a * Math.pow(10, aDecimalPlaces));
- const bInt = Math.round(b * Math.pow(10, bDecimalPlaces));
-
- // 计算结果并调整小数位数
- const result = (aInt / bInt) * Math.pow(10, bDecimalPlaces - aDecimalPlaces);
-
- // 四舍五入到指定精度
- return Math.round(result * Math.pow(10, precision)) / Math.pow(10, precision);
- }
-
- // 计算复利
- static calculateCompoundInterest(principal, rate, time, compoundFrequency = 1) {
- // A = P(1 + r/n)^(nt)
- // 其中 P 是本金,r 是年利率,t 是时间(年),n 是复利频率
- const base = FinancialCalculator.add(1, FinancialCalculator.divide(rate, compoundFrequency));
- const exponent = time * compoundFrequency;
-
- // 使用精确计算计算幂
- let result = 1;
- for (let i = 0; i < exponent; i++) {
- result = FinancialCalculator.multiply(result, base);
- }
-
- return FinancialCalculator.multiply(principal, result);
- }
-
- // 计算贷款月供
- static calculateLoanPayment(principal, annualRate, years) {
- // 月利率
- const monthlyRate = FinancialCalculator.divide(annualRate, 12);
-
- // 总月数
- const totalMonths = years * 12;
-
- // 如果月利率为0,直接返回本金除以月数
- if (monthlyRate === 0) {
- return FinancialCalculator.divide(principal, totalMonths);
- }
-
- // 计算月供:P = (r * PV) / (1 - (1 + r)^(-n))
- const numerator = FinancialCalculator.multiply(monthlyRate, principal);
-
- // 计算(1 + r)^(-n)
- const base = FinancialCalculator.add(1, monthlyRate);
- let denominatorBase = 1;
- for (let i = 0; i < totalMonths; i++) {
- denominatorBase = FinancialCalculator.multiply(denominatorBase, base);
- }
- const denominator = FinancialCalculator.subtract(1, FinancialCalculator.divide(1, denominatorBase));
-
- return FinancialCalculator.divide(numerator, denominator);
- }
- }
- // 使用示例:精确计算
- console.log(FinancialCalculator.add(0.1, 0.2)); // 0.3
- console.log(FinancialCalculator.multiply(0.1, 0.2)); // 0.02
- // 计算复利
- const principal = 1000; // 本金1000元
- const rate = 0.05; // 年利率5%
- const time = 10; // 10年
- const compoundFrequency = 12; // 每月复利
- const finalAmount = FinancialCalculator.calculateCompoundInterest(principal, rate, time, compoundFrequency);
- console.log(`复利计算结果: ${finalAmount.toFixed(2)}元`);
- // 计算贷款月供
- const loanPrincipal = 200000; // 贷款20万
- const loanRate = 0.049; // 年利率4.9%
- const loanYears = 30; // 30年
- const monthlyPayment = FinancialCalculator.calculateLoanPayment(loanPrincipal, loanRate, loanYears);
- console.log(`贷款月供: ${monthlyPayment.toFixed(2)}元`);
- // 货币格式化
- function formatCurrency(amount, locale = 'zh-CN', currency = 'CNY') {
- return new Intl.NumberFormat(locale, {
- style: 'currency',
- currency: currency,
- minimumFractionDigits: 2
- }).format(amount);
- }
- console.log(formatCurrency(finalAmount)); // 例如:"¥1,647.01"
- console.log(formatCurrency(monthlyPayment)); // 例如:"¥1,061.45"
复制代码
总结
JavaScript数字处理是Web开发中的基础技能,掌握各种数字处理技巧可以帮助我们更高效地解决实际问题。本指南从JavaScript数字的基础知识开始,介绍了数字类型、表示方法和特殊值,然后深入探讨了基础数学运算、数字格式化、高级数字处理技术,以及在实际开发中的应用场景。
我们学习了如何处理JavaScript中的浮点数精度问题,如何使用BigInt处理大整数,以及如何进行精确的金融计算。我们还探讨了数字范围限制、验证和性能优化等实用技巧,并通过数据可视化、游戏开发和金融计算等实际应用场景,展示了这些技术的实际应用。
通过掌握这些数字处理技巧,你将能够更加自信地处理JavaScript中的各种数字计算任务,避免常见的陷阱,提高代码的准确性和性能。无论你是初学者还是有经验的开发者,这些知识都将对你的开发工作有所帮助。
希望本指南能够成为你在JavaScript数字处理方面的宝贵资源,帮助你在日常开发中更加高效地解决数字相关的问题。 |
|