简介
Math.js 是一个强大的 JavaScript 和 Node.js 数学库。它拥有灵活的表达式解析器,支持符号计算,内置大量函数和常量,并提供集成解决方案,可处理各种数据类型,例如数字、大数、复数、分数、单位和矩阵。功能强大且易于使用。
安装
npm install mathjs
使用
import { create } from "mathjs";
const math = create(all);
console.log(math.evaluate("1 + 2 * 3")); // 7
常用函数
基础函数
math.abs(-1); // 1
math.add(2, 3); // 5
math.ceil(3.14); // 4
math.floor(3.14); // 3
math.log(10); // 2.302585092994046
math.max(1, 2, 3); // 3
math.min(1, 2, 3); // 1
math.pow(2, 3); // 8
math.round(3.14); // 3
math.sqrt(9); // 3
math.sub(5, 3); // 2
math.trunc(3.14); // 3
Evaluate 表达式
math.evaluate("2 + 3 * 4"); // 14
BigNumber 大数字
const math = create(all, {
number: "BigNumber",
precision: 64,
});
console.log(math.evaluate("0.1 + 0.2").toString()); // "0.3"
math.bignumber(0.1 + 0.2); // 0.30000000000000004
math.bignumber(0.1).plus(0.2); // 0.3
不启用 bigNumber 配置,默认使用 number 类型, math.evaluate(“0.1 + 0.2”)结果为 0.30000000000000004
math.js 中大多数函数都支持 bigNumber 类型,但部分函数不支持,如 math.random()。
一些容易误入的误差,觉得使用了 bignumber 就可以避免浮点数精度问题,方法不对,也是不能解决问题的。
math.add(0.1, 0.2); // 0.30000000000000004
理想上,结果应该是 0.3,但实际结果却是 0.30000000000000004。这是因为 JavaScript 中的浮点数表示方式导致的精度问题。
那应该如何使用 bigNumber 来避免这个问题呢?
math.add(math.bignumber(0.1), math.bignumber(0.2)); // 0.3
通过将数字转换为 bigNumber 类型,可以避免浮点数精度问题,得到正确的结果。
Bigint 大整数
const math = create(all, {
number: "bigint",
});
console.log(math.evaluate("70000000000000000123")); // 70000000000000000123n
注意:bigint 只能用于整数运算,不能用于浮点数运算。因此不能适用于三角函数。因为它会转换为 number,再执函数。
console.log(math.sin(2n)); // 0.9092974268256817
Fraction 分数
const math = create(all, {
number: "Fraction",
});
console.log(math.fraction("2/5")); // Fraction { s: 1n, d: 5n, n: 2n }
Complex 复数
const math = create(all, {
number: "Complex",
});
console.log(math.complex("2+3i")); // Complex { re: 2, im: 3 }
Unit 单位
const math = create(all, {
number: "Unit",
});
console.log(math.unit("5cm")); // Unit { prefix: 'c', unit: 'm', value: 0.05 }
Matrix 矩阵
const math = create(all, {
matrix: "Matrix",
});
console.log(
math.matrix([
[1, 2],
[3, 4],
])
); // Matrix [[1, 2], [3, 4]]
使用场景
计算器
import { create, all } from "mathjs";
import { useState } from "react";
const math = create(all, {
number: "BigNumber",
});
export default function MathDemo() {
const [display, setDisplay] = useState("0");
const [equation, setEquation] = useState("");
const [isNewNumber, setIsNewNumber] = useState(true);
const [isScientificMode, setIsScientificMode] = useState(false);
const handleNumber = (num) => {
if (isNewNumber) {
setDisplay(num);
setIsNewNumber(false);
} else {
setDisplay(display + num);
}
};
const handleOperator = (operator) => {
setEquation(display + " " + operator + " ");
setIsNewNumber(true);
};
const handleScientificFunction = (func) => {
try {
let result;
switch (func) {
case "sin":
result = math.sin(math.unit(display, "deg"));
break;
case "cos":
result = math.cos(math.unit(display, "deg"));
break;
case "tan":
result = math.tan(math.unit(display, "deg"));
break;
case "log":
result = math.log10(parseFloat(display));
break;
case "ln":
result = math.log(parseFloat(display));
break;
case "sqrt":
result = math.sqrt(parseFloat(display));
break;
case "square":
result = math.pow(parseFloat(display), 2);
break;
case "pi":
result = math.pi;
break;
case "e":
result = math.e;
break;
default:
return;
}
setDisplay(result.toString());
setIsNewNumber(true);
} catch (error) {
setDisplay("Error");
setIsNewNumber(true);
}
};
const handleEqual = () => {
try {
const result = math.evaluate(equation + display);
setDisplay(result.toString());
setEquation("");
setIsNewNumber(true);
} catch (error) {
setDisplay("Error");
setEquation("");
setIsNewNumber(true);
}
};
const handleClear = () => {
setDisplay("0");
setEquation("");
setIsNewNumber(true);
};
const handleBackspace = () => {
if (display.length > 1) {
setDisplay(display.slice(0, -1));
} else {
setDisplay("0");
setIsNewNumber(true);
}
};
const basicButtons = [
{ label: "7", onClick: () => handleNumber("7") },
{ label: "8", onClick: () => handleNumber("8") },
{ label: "9", onClick: () => handleNumber("9") },
{ label: "÷", onClick: () => handleOperator("/") },
{ label: "4", onClick: () => handleNumber("4") },
{ label: "5", onClick: () => handleNumber("5") },
{ label: "6", onClick: () => handleNumber("6") },
{ label: "×", onClick: () => handleOperator("*") },
{ label: "1", onClick: () => handleNumber("1") },
{ label: "2", onClick: () => handleNumber("2") },
{ label: "3", onClick: () => handleNumber("3") },
{ label: "-", onClick: () => handleOperator("-") },
{ label: "0", onClick: () => handleNumber("0") },
{ label: ".", onClick: () => handleNumber(".") },
{ label: "=", onClick: handleEqual },
{ label: "+", onClick: () => handleOperator("+") },
];
const scientificButtons = [
{ label: "sin", onClick: () => handleScientificFunction("sin") },
{ label: "cos", onClick: () => handleScientificFunction("cos") },
{ label: "tan", onClick: () => handleScientificFunction("tan") },
{ label: "log", onClick: () => handleScientificFunction("log") },
{ label: "ln", onClick: () => handleScientificFunction("ln") },
{ label: "√", onClick: () => handleScientificFunction("sqrt") },
{ label: "x²", onClick: () => handleScientificFunction("square") },
{ label: "π", onClick: () => handleScientificFunction("pi") },
{ label: "e", onClick: () => handleScientificFunction("e") },
{ label: "(", onClick: () => handleNumber("(") },
{ label: ")", onClick: () => handleNumber(")") },
{ label: "^", onClick: () => handleOperator("^") },
];
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-black">
<div className="w-96 bg-zinc-900 rounded-xl shadow-2xl p-6 border border-zinc-800">
<div className="mb-6">
<div className="text-right text-zinc-500 text-sm h-6 font-mono">
{equation}
</div>
<div className="text-right text-4xl font-bold h-14 text-white font-mono">
{display}
</div>
</div>
<div className="flex justify-between mb-4">
<button
onClick={handleClear}
className="bg-zinc-800 text-white px-4 py-2 rounded-lg hover:bg-zinc-700 transition-colors font-mono"
>
Clear
</button>
<button
onClick={handleBackspace}
className="bg-zinc-800 text-white px-4 py-2 rounded-lg hover:bg-zinc-700 transition-colors font-mono"
>
←
</button>
<button
onClick={() => setIsScientificMode(!isScientificMode)}
className="bg-zinc-800 text-white px-4 py-2 rounded-lg hover:bg-zinc-700 transition-colors font-mono"
>
{isScientificMode ? "Basic" : "Scientific"}
</button>
</div>
{isScientificMode && (
<div className="grid grid-cols-4 gap-3 mb-4">
{scientificButtons.map((button, index) => (
<button
key={index}
onClick={button.onClick}
className="bg-zinc-800 hover:bg-zinc-700 p-3 rounded-lg text-sm font-mono text-white transition-all duration-200 hover:shadow-lg hover:shadow-zinc-700/20"
>
{button.label}
</button>
))}
</div>
)}
<div className="grid grid-cols-4 gap-3">
{basicButtons.map((button, index) => (
<button
key={index}
onClick={button.onClick}
className={`p-4 rounded-lg text-lg font-mono transition-all duration-200 ${
button.label === "="
? "bg-white text-black hover:bg-zinc-200 hover:shadow-lg hover:shadow-white/20"
: "bg-zinc-800 text-white hover:bg-zinc-700 hover:shadow-lg hover:shadow-zinc-700/20"
}`}
>
{button.label}
</button>
))}
</div>
</div>
</div>
);
}
购物车计算
import React, { useState, useEffect } from "react";
import { create, all } from "mathjs";
const math = create(all, {
number: "BigNumber",
precision: 20,
});
const ShoppingCart = () => {
const [items, setItems] = useState([
{ id: 1, name: "Product 1", price: "1299.99", quantity: 1 },
{ id: 2, name: "Product 2", price: "49.99", quantity: 1 },
{ id: 3, name: "Product 3", price: "599.99", quantity: 1 },
]);
const [cartTotal, setCartTotal] = useState("0");
const [discount, setDiscount] = useState("0");
const [tax, setTax] = useState("0");
const [finalTotal, setFinalTotal] = useState("0");
const calculateTotals = () => {
try {
// Calculate subtotal
const subtotal = items.reduce((acc, item) => {
return math.add(
acc,
math.multiply(
math.bignumber(item.price),
math.bignumber(item.quantity)
)
);
}, math.bignumber(0));
// Calculate discount (10% if total > 1000)
const discountAmount =
math.compare(subtotal, 1000) === 1
? math.multiply(subtotal, 0.1)
: math.bignumber(0);
// Calculate tax (8%)
const taxAmount = math.multiply(
math.subtract(subtotal, discountAmount),
0.08
);
// Calculate final total
const total = math.add(
math.subtract(subtotal, discountAmount),
taxAmount
);
setCartTotal(math.format(subtotal, { precision: 2 }));
setDiscount(math.format(discountAmount, { precision: 2 }));
setTax(math.format(taxAmount, { precision: 2 }));
setFinalTotal(math.format(total, { precision: 2 }));
} catch (error) {
console.error("Calculation error:", error);
}
};
useEffect(() => {
calculateTotals();
}, [items]);
const handleQuantityChange = (id, newQuantity) => {
if (newQuantity < 1) return;
setItems(
items.map((item) =>
item.id === id ? { ...item, quantity: newQuantity } : item
)
);
};
const handleRemoveItem = (id) => {
setItems(items.filter((item) => item.id !== id));
};
return (
<div className="min-h-screen bg-zinc-900 text-white p-8">
<div className="max-w-4xl mx-auto">
<h1 className="text-4xl font-bold mb-8 text-center">Shopping Cart</h1>
<div className="bg-zinc-800 rounded-xl p-6 shadow-2xl">
<div className="space-y-4">
{items.map((item) => (
<div
key={item.id}
className="flex items-center justify-between bg-zinc-700 p-4 rounded-lg"
>
<div className="flex-1">
<h3 className="text-xl font-semibold">{item.name}</h3>
<p className="text-zinc-300">${item.price}</p>
</div>
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-2">
<button
onClick={() =>
handleQuantityChange(item.id, item.quantity - 1)
}
className="bg-zinc-600 hover:bg-zinc-500 w-8 h-8 rounded-lg flex items-center justify-center transition-colors"
>
-
</button>
<span className="w-8 text-center">{item.quantity}</span>
<button
onClick={() =>
handleQuantityChange(item.id, item.quantity + 1)
}
className="bg-zinc-600 hover:bg-zinc-500 w-8 h-8 rounded-lg flex items-center justify-center transition-colors"
>
+
</button>
</div>
<button
onClick={() => handleRemoveItem(item.id)}
className="bg-red-500 hover:bg-red-600 px-4 py-2 rounded-lg transition-colors"
>
Remove
</button>
</div>
</div>
))}
</div>
<div className="mt-8 space-y-2 border-t border-zinc-700 pt-4">
<div className="flex justify-between text-lg">
<span>Subtotal:</span>
<span>${cartTotal}</span>
</div>
<div className="flex justify-between text-lg text-green-400">
<span>Discount (10% if total {">"} $1000):</span>
<span>-${discount}</span>
</div>
<div className="flex justify-between text-lg">
<span>Tax (8%):</span>
<span>${tax}</span>
</div>
<div className="flex justify-between text-2xl font-bold mt-4 pt-4 border-t border-zinc-700">
<span>Total:</span>
<span>${finalTotal}</span>
</div>
</div>
</div>
</div>
</div>
);
};
export default ShoppingCart;
原文链接:https://code.ifrontend.net/archives/355,转载请注明出处。
评论0