слова, написанные впереди
Эта статья представляет собой идею от начального решения до окончательного решения, длина статьи велика.
Хотя это статья, начинающаяся с 0, скачок мышления в середине может быть относительно большим.
Анализ кода находится в анализе идеи и комментариях статьи, а полный текст поможет понять несколько ключевых слов
- Number.MAX_SAFE_INTEGER и Number.MIN_SAFE_INTEGER
- строка 15 длины
- padStart и padEnd
Анализ идеи заполнения ямы
Я считаю, что многие фронтенды знают этот волшебный код.
console.log(0.1 + 0.2 === 0.3) // false
console.log(0.3 - 0.2 === 0.1) // false
В Интернете есть много статей, объясняющих это, поэтому я не буду анализировать это здесь.
По крайней мере, мы можем знать, что есть проблема со сложением и вычитанием десятичных знаков!
Как решить сложение и вычитание десятичных дробей? Есть идея:
既然小数加减存在问题,那么避开这个问题。
直接把小数转换成整数后加减计算,这总可以吧。
Яма десятичных дробей теперь переведена в целые числа, а потом посмотрите на ямы сложения и вычитания целых чисел...
const max = Number.MAX_SAFE_INTEGER
console.log(max) // 9007199254740991
console.log(max + 2) // 9007199254740992
const min = Number.MIN_SAFE_INTEGER
console.log(min) // -9007199254740991
console.log(min - 2) // -9007199254740992
Number.MAX_SAFE_INTEGERЧто это такое?
согласно сMDNвнутри определения
常量表示在 JavaScript 中最大的安全整数
Аналогично можно видеть, чтоNumber.MIN_SAFE_INTEGERЭто самая маленькая целочисленная безопасность
Целочисленные расчеты и вычитания в пределах максимальной безопасности и минимального целого числа безопасности целое число крепко
Безопасен ли результат расчета? хм, кажется, есть проблема...
console.log(10 ** 21) // 1e+21
console.log(999999999999999999999) // 1e+21
Как видно из вышеприведенных результатов, невозможно терпеть
1.最后的输出结果显示的是科学计数法
2.科学计数法表示的数并不能准确知道真实的数是多少
Так как есть такая проблема с отображением чисел, то результаты ввода и результаты вывода представлены строками
console.log(`${10 ** 21}`) // '1e+21'
console.log('' + 10 ** 21) // '1e+21'
console.log((10 ** 21).toString()) // '1e+21'
Мы обнаружили, что даже если она будет напрямую преобразована в строку, она все равно будет отображаться в экспоненциальном представлении, поэтому вы можете напрямую ввести строку и пропустить процесс преобразования в строку.
Решите яму целочисленного сложения
Вот сначала попробуй решить задачу на сложение целых чисел
Вот несколько возможностей
1.输入的数字都在安全整数以内相加之后,且计算的结果也在安全整数之内,则直接输出结果
2.如果不满足上面条件的...(等下再说)
const MAX = Number.MAX_SAFE_INTEGER
const MIN = Number.MIN_SAFE_INTEGER
/**
* @param { number } num 需要检查的整数
* @return { boolean } 返回数字是否为安全的整数
*/
function isSafeNumber(num) {
// 即使 num 成了科学计数法也能正确的和 MAX, MIN 比较大小
return MIN <= num && num <= MAX
}
/**
* @param { string } a 相加的第一个整数字符串
* @param { string } b 相加的第二个整数字符串
* @return { string } 返回相加的结果
*/
function IntAdd(a = '', b = '') {
let resulte = '0'
const intA = Number(a), intB = Number(b)
if (intA === 0) return b
if (intB === 0) return a
if (isSafeNumber(intA) && isSafeNumber(intB) && isSafeNumber(intA + intB)) {
resulte = intA + intB
} else {
resulte = IntCalc(a, b)
}
return resulte
}
function IntCalc(a, b) {
// TODO
}
Что делать, если вышеуказанные условия не выполняются?
Мышление автора такое
获取数字转成字符串拆分成多个部分(数组),每一个部分的长度为 Number.MAX_SAFE_INTEGER 转成字符串后的长度减一(15),长度不足15的用字符‘0’填充首部,再计算每个部分的结果后拼接在一起
同时考虑到正负号的问题,拆分后的计算需要带上符号
Причина длины минус один заключается в том, что все вычисления в каждой из следующих частей безопасны, и их не нужно рассматривать как число, которое оценивается как безопасное целое число.
В то же время есть проблемы в результатах каждой части расчета и авторского решения.
注意:下面会使用15这个数字,15上面说过了,是Number.MAX_SAFE_INTEGER的长度减一
1.计算结果为0
那么这个部分赋值15个字符‘0’组成的字符串,即‘000000000000000’
2.计算结果为负数
那么向上一级数组借10的15次方,同时高位(下一级数组)减一,低位用10的15次方再加上这个负数,做为这个部分的结果
3.计算结果为正数,判断长度:
如果长度超过15,那么去掉结果的第一位字符(因为进位,第一个字符一定是‘1’),同时高位(下一级数组)加一
如果长度没有超过15,向首部补充0直到长度足够15
如果长度等于15,直接添加到结果中
Сразу переходите к коду, в нем будут подробные комментарии
const MAX = Number.MAX_SAFE_INTEGER
const MIN = Number.MIN_SAFE_INTEGER
const intLen = `${MAX}`.length - 1 // 下面会频繁用到的长度 15
function isSafeNumber(num) {
// 即使 num 成了科学计数法也能正确的和 MAX, MIN 比较大小
return MIN <= num && num <= MAX
}
// 整数加法函数入口
function intAdd(a = '0', b = '0') {
const statusObj = checkNumber(a, b)
if (!statusObj.status) {
return statusObj.data
} else {
const tagA = Number(a) < 0, tagB = Number(b) < 0
const strA = `${a}`, strB = `${b}`
const lenA = tagA ? strA.length - 1 : strA.length
const lenB = tagB ? strB.length - 1 : strB.length
const maxLen = Math.max(lenA, lenB)
const padLen = Math.ceil(maxLen / intLen) * intLen // 即为会用到的整个数组长度
const newA = tagA ? `-${strA.slice(1).padStart(padLen, '0')}` : strA.padStart(padLen, '0')
const newB = tagB ? `-${strB.slice(1).padStart(padLen, '0')}` : strB.padStart(padLen, '0')
let result = intCalc(newA, newB)
// 去掉正负数前面无意义的字符 ‘0’
const numberResult = Number(result)
if (numberResult > 0) {
while (result[0] === '0') {
result = result.slice(1)
}
} else if (numberResult < 0) {
while (result[1] === '0') {
result = '-' + result.slice(2)
}
} else {
result = '0'
}
console.log(result)
return result
}
}
/**
* @param { string } a 相加的第一个整数字符串
* @param { string } b 相加的第二个整数字符串
* @return { string } 返回相加的结果
*/
function intCalc(a, b) {
let result = '0'
const intA = Number(a), intB = Number(b)
// 判断是否为安全数,不为安全数的操作进入复杂计算模式
if (isSafeNumber(intA) && isSafeNumber(intB) && isSafeNumber(intA + intB)) {
result = `${intA + intB}`
} else {
const sliceA = a.slice(1), sliceB = b.slice(1)
if(a[0] === '-' && b[0] === '-') {
// 两个数都为负数,取反后计算,结果再取反
result = '-' + calc(sliceA, sliceB, true)
} else if (a[0] === '-') {
// 第一个数为负数,第二个数为正数的情况
const newV = compareNumber(sliceA, b)
if (newV === 1) {
// 由于 a 的绝对值比 b 大,为了确保返回结果为正数,a的绝对值作为第一个参数
result = '-' + calc(sliceA, b, false)
} else if (newV === -1) {
// 道理同上
result = calc(b, sliceA, false)
}
} else if (b[0] === '-') {
// 第一个数为正数,第二个数为负数的情况
const newV = compareNumber(sliceB, a)
if (newV === 1) {
// 由于 b 的绝对值比 a 大,为了确保返回结果为正数,b的绝对值作为第一个参数
result = '-' + calc(sliceB, a, false)
} else if (newV === -1) {
// 道理同上
result = calc(a, sliceB, false)
}
} else {
// 两个数都为正数,直接计算
result = calc(a, b, true)
}
}
return result
}
/**
* @param { string } a 比较的第一个整数字符串
* @param { string } b 比较的第二个整数字符串
* @return { object } 返回是否要退出函数的状态和退出函数返回的数据
*/
function checkNumber(a, b) {
const obj = {
status: true,
data: null
}
const typeA = typeof(a), typeB = typeof(b)
const allowTypes = ['number', 'string']
if (!allowTypes.includes(typeA) || !allowTypes.includes(typeB)) {
console.error('参数中存在非法的数据,数据类型只支持 number 和 string')
obj.status = false
obj.data = false
}
if (Number.isNaN(a) || Number.isNaN(b)) {
console.error('参数中不应该存在 NaN')
obj.status = false
obj.data = false
}
const intA = Number(a), intB = Number(b)
if (intA === 0) {
obj.status = false
obj.data = b
}
if (intB === 0) {
obj.status = false
obj.data = a
}
const inf = [Infinity, -Infinity]
if (inf.includes(intA) || inf.includes(intB)) {
console.error('参数中存在Infinity或-Infinity')
obj.status = false
obj.data = false
}
return obj
}
/**
* @param { string } a 比较的第一个整数字符串
* @param { string } b 比较的第二个整数字符串
* @return { boolean } 返回第一个参数与第二个参数的比较
*/
function compareNumber(a, b) {
if (a === b) return 0
if (a.length > b.length) {
return 1
} else if (a.length < b.length) {
return -1
} else {
for (let i=0; i<a.length; i++) {
if (a[i] > b[i]) {
return 1
} else if (a[i] < b[i]) {
return -1
}
}
}
}
/**
* @param { string } a 相加的第一个整数字符串
* @param { string } b 相加的第二个整数字符串
* @param { string } type 两个参数是 相加(true) 还是相减(false)
* @return { string } 返回相加的结果
*/
function calc(a, b, type = true) {
const arr = [] // 保存每个部分计算结果的数组
for (let i=0; i<a.length; i+=intLen) {
// 每部分长度 15 的裁取字符串
const strA = a.slice(i, i + intLen)
const strB = b.slice(i, i + intLen)
const newV = Number(strA) + Number(strB) * (type ? 1 : -1) // 每部分的计算结果,暂时不处理
arr.push(`${newV}`)
}
let num = '' // 连接每个部分的字符串
for (let i=arr.length-1; i>=0; i--) {
if (arr[i] > 0) {
// 每部分结果大于 0 的处理方案
const str = `${arr[i]}`
if (str.length < intLen) {
// 长度不足 15 的首部补充字符‘0’
num = str.padStart(intLen, '0') + num
} else if (str.length > intLen) {
// 长度超过 15 的扔掉第一位,下一部分进位加一
num = str.slice(1) + num
if (i >= 1 && str[0] !== '0') arr[i-1]++
else num = '1' + num
} else {
// 长度等于 15 的直接计算
num = str + num
}
} else if(arr[i] < 0) {
// 每部分结果小于 0 的处理方案,借位 10的15次方计算,结果恒为正数,首部填充字符‘0’到15位
const newV = `${10 ** intLen + Number(arr[i])}`
num = newV.padStart(intLen, '0') + num
if (i >= 1) arr[i-1]--
} else {
// 每部分结果等于 0 的处理方案,连续15个字符‘0’
num = '0'.padStart(intLen, '0') + num
}
}
return num
}
Результаты теста
Пожалуйста, посмотрите эту часть кодаздесь
console.log(MAX) // 9007199254740991
intAdd(MAX, '2') // '9007199254740993'
intAdd(MAX, '10000000000000000') // '19007199254740991'
// 下面测试10的二十一次方的数据 1000000000000000000000
intAdd(MAX, '1000000000000000000000') // '1000009007199254740991'
intAdd(MAX, `-${10 ** 16}`) // '-992800745259009'
// 仍然存在一个问题,就是不要使用计算中的字符串,如下
intAdd(MAX, `${10 ** 21}`) // '10.0000000071992548e+21'
intAdd(MAX, `-${10 ** 21}`) // '0'
Конечно, учитывая, что в общих вычислениях не используются большие числа, добавление записи строк кажется странным.Вы можете добавить суждение в функцию, которая является подсказкой научной нотации, и преобразовать ее в десятичные числа для улучшения кода.
// 整数加法函数入口
function intAdd(a = '0', b = '0') {
const statusObj = checkNumber(a, b)
if (!statusObj.status) {
return statusObj.data
} else {
let newA, newB, maxLen
const tagA = Number(a) < 0, tagB = Number(b) < 0
const strA = `${a}`, strB = `${b}`
const reg = /^\-?(\d+)(\.\d+)?e\+(\d+)$/
if(reg.test(a) || reg.test(b)) {
console.warn('由于存在科学计数法,计算结果不一定准确,请转化成字符串后计算')
a = strA.replace(reg, function(...rest){
const str = rest[2] ? rest[1] + rest[2].slice(1) : rest[1]
return str.padEnd(Number(rest[3]) + 1, '0')
})
b = strB.replace(reg, function(...rest){
const str = rest[2] ? rest[1] + rest[2].slice(1) : rest[1]
return str.padEnd(Number(rest[3]) + 1, '0')
})
maxLen = Math.max(a.length, b.length)
} else {
const lenA = tagA ? strA.length - 1 : strA.length
const lenB = tagB ? strB.length - 1 : strB.length
maxLen = Math.max(lenA, lenB)
}
const padLen = Math.ceil(maxLen / intLen) * intLen // 即为会用到的整个数组长度
newA = tagA ? `-${strA.slice(1).padStart(padLen, '0')}` : strA.padStart(padLen, '0')
newB = tagB ? `-${strB.slice(1).padStart(padLen, '0')}` : strB.padStart(padLen, '0')
let result = intCalc(newA, newB)
// 去掉正负数前面无意义的字符 ‘0’
const numberResult = Number(result)
if (numberResult > 0) {
while (result[0] === '0') {
result = result.slice(1)
}
} else if (numberResult < 0) {
while (result[1] === '0') {
result = '-' + result.slice(2)
}
} else {
result = '0'
}
console.log(result)
return result
}
}
продолжить тестирование кода
Пожалуйста, посмотрите эту часть кодаздесь
// 警告:由于存在科学计数法,计算结果不一定准确,请转化成字符串后计算
intAdd(MAX, 10 ** 21) // '1000009007199254740991'
// 警告:由于存在科学计数法,计算结果不一定准确,请转化成字符串后计算
intAdd(MAX, 10 ** 21 + 2) // '1000009007199254740991'
intAdd(MAX, NaN) // 报错:参数中不应该存在 NaN
intAdd(MAX, {}) // 报错:参数中存在非法的数据,数据类型只支持 number 和 string
// 大数计算
intAdd('9037499254750994', '-9007299251310995') // '30200003439999'
intAdd('8107499231750996', '-9007299254310995') // '-899800022559999'
intAdd('-9907492547350994', '9007399254750995') // '-900093292599999'
intAdd('9997492547350994', '9997399254750995') // '19994891802101989'
intAdd('-9997492547350994', '-9997399254750995') // '-19994891802101989'
intAdd('-4707494254750996000004254750996', '9707494254750996007299232150995') // '5000000000000000007294977399999'
intAdd('-4707494254750996900004254750996', '9707494254750996007299232150995') // '4999999999999999107294977399999'
Решите ямы целочисленного вычитания
Сложение и вычитание одинаковы, нужно использовать только второй параметр для расчета операции сложения, поскольку шаблон был извлечен, можно напрямую определить функцию вычитания.
// 整数减法函数入口
function intSub(a = '0', b = '0') {
const newA = `${a}`
const newB = Number(b) > 0 ? `-${b}`: `${b}`.slice(1)
const statusObj = checkNumber(newA, newB)
if (!statusObj.status) {
return statusObj.data
} else {
const result = IntAdd(newA, newB)
return result
}
}
Результаты теста
IntSub('9037499254750994', '-9007299251310995') // '18044798506061989'
IntSub('8107499231750996', '-9007299254310995') // '17114798486061991'
IntSub('-9907492547350994', '9007399254750995') // '-18914891802101989'
IntSub('9997492547350994', '9997399254750995') // '93292599999'
IntSub('-4707494254750996000004254750996', '9707494254750996007299232150995') // '-14414988509501992007303486901991'
IntSub('-4707494254750996900004254750996', '9707494254750996007299232150995') // '-14414988509501992907303486901991'
Решите яму десятичного сложения
Яма десятичного сложения и вычитания в JavaScript связана с проблемой вычисления точности с плавающей запятой.В Интернете можно найти множество статей по теме, но автор не намерен начинать с вычисления с плавающей запятой.
Так как задача сложения и вычитания целых чисел уже решалась ранее, то вычисление десятичных дробей также можно реализовать, используя принцип сложения и вычитания целых чисел.
整数加法代码中经常出现 `padStart` 这个向前补齐的函数,因为在整数前加字符‘0’的对本身没有影响。
小数也有这个原理,往尾部补‘0’同样对小数没有影响,然后再补齐后的数通过整数加减来计算。
Реализация на основе идеи целочисленного сложения
// 小数加法函数入口
function floatAdd(a = '0', b = '0') {
const statusObj = checkNumber(a, b)
if (!statusObj.status) {
return statusObj.data
} else {
const strA = `${a}`.split('.'), strB = `${b}`.split('.')
let newA = strA[1], newB = strB[1]
const maxLen = Math.max(newA.length, newB.length)
const floatLen = Math.ceil(maxLen / intLen) * intLen
newA = newA.padEnd(floatLen, '0')
newB = newB.padEnd(floatLen, '0')
newA = strA[0][0] === '-' ? `-${newA}` : newA
newB = strB[0][0] === '-' ? `-${newB}` : newB
let result = intCalc(newA, newB)
let tag = true, numResult = Number(result)
// 去掉正负数后面无意义的字符 ‘0’
if (numResult !== 0) {
if (numResult < 0) {
result = result.slice(1)
tag = false
}
result = result.length === floatLen ? `0.${result}` : `1.${result.slice(1)}`
result = tag ? result : `-${result}`
let index = result.length - 1
while (result[index] === '0') {
result = result.slice(0, -1)
index--
}
} else {
result = '0'
}
console.log(result)
return result
}
}
Результаты теста
Пожалуйста, посмотрите эту часть кодаздесь
floatAdd('0.9037499254750994', '-0.9007299251310995') // '0.0030200003439999'
floatAdd('0.8107499231750996', '-0.9007299254310995') // '-0.0899800022559999'
floatAdd('-0.9907492547350994', '0.9007399254750995') // '-0.0900093292599999'
floatAdd('0.9997492547350994', '0.9997399254750995') // '1.9994891802101989'
floatAdd('-0.9997492547350994', '-0.9997399254750995') // '-1.9994891802101989'
floatAdd('-0.4707494254750996000004254750996', '0.9707494254750996007299232150995') // '0.5000000000000000007294977399999'
floatAdd('-0.4707494254750996900004254750996', '0.9707494254750996007299232150995') // '0.4999999999999999107294977399999'
Решить яму десятичного вычитания
По тому же принципу, что и целочисленное вычитание, функция вычитания может быть определена напрямую.
// 小数减法函数入口
function floatSub(a = '0', b = '0') {
const newA = `${a}`
const newB = Number(b) > 0 ? `-${b}`: `${b.slice(1)}`
const statusObj = checkNumber(newA, newB)
if (!statusObj.status) {
return statusObj.data
} else {
const result = floatAdd(newA, newB)
return result
}
}
Результаты теста
Пожалуйста, смотрите приведенный выше кодздесь
floatSub('0.9037499254750994', '-0.9007299251310995') // '1.8044798506061989'
floatSub('0.8107499231750996', '-0.9007299254310995') // '1.7114798486061991'
floatSub('-0.9907492547350994', '0.9007399254750995') // '-1.8914891802101989'
floatSub('0.9997492547350994', '0.9997399254750995') // '0.0000093292599999'
floatSub('-0.9997492547350994', '-0.9997399254750995') // '-0.0000093292599999'
floatSub('-0.4707494254750996000004254750996', '0.9707494254750996007299232150995') // '-1.4414988509501992007303486901991'
floatSub('-0.4707494254750996900004254750996', '0.9707494254750996007299232150995') // '-1.4414988509501992907303486901991'
Решить общую проблему добавления целых чисел и десятичных случаев
Поскольку многие из чисел, возникающих в фактическом количестве, интегрированы, в следующем исходном анализе.
这里的解决思路仍然是往前补0和往后补0
把整数和小数都补充完整后,合在一起进行整数相加
最后根据之前保存的整数的长度,插入小数点
剩下的就是把无意义的0排除掉,输出结果
Здесь, когда одна сторона не имеет десятичной дроби
// 任意数加法函数入口
function allAdd(a = '0', b = '0') {
const statusObj = checkNumber(a, b)
if (!statusObj.status) {
return statusObj.data
} else {
const strA = `${a}`.split('.'), strB = `${b}`.split('.')
let intAs = strA[0], floatA = strA.length === 1 ? '0' : strA[1]
let intBs = strB[0], floatB = strB.length === 1 ? '0' : strB[1]
const tagA = intAs > 0, tagB = intBs > 0
const maxIntLen = Math.max(intAs.length, intBs.length)
const arrIntLen = Math.ceil(maxIntLen / intLen) * intLen
const maxFloatLen = Math.max(floatA.length, floatB.length)
const arrFloatLen = Math.ceil(maxFloatLen / intLen) * intLen
intAs = tagA ? intAs.padStart(arrIntLen, '0') : intAs.slice(1).padStart(arrIntLen, '0')
intBs = tagB ? intBs.padStart(arrIntLen, '0') : intBs.slice(1).padStart(arrIntLen, '0')
let newA = floatA === '0' ? intAs + '0'.padEnd(arrFloatLen, '0') : intAs + floatA.padEnd(arrFloatLen, '0')
let newB = floatB === '0' ? intBs + '0'.padEnd(arrFloatLen, '0') : intBs + floatB.padEnd(arrFloatLen, '0')
newA = tagA ? newA : `-${newA}`
newB = tagB ? newB : `-${newB}`
let result = intCalc(newA, newB)
const numResult = Number(result)
if (result.length > arrIntLen) {
result = result.slice(0, -arrFloatLen) + '.' + result.slice(-arrFloatLen)
}
// 去掉正负数前面后面无意义的字符 ‘0’
if (numResult !== 0) {
if (numResult > 0) {
while (result[0] === '0') {
result = result.slice(1)
}
} else if (numResult < 0) {
while (result[1] === '0') {
result = '-' + result.slice(2)
}
result = result.slice(1)
tag = false
}
let index = result.length - 1
while (result[index] === '0') {
result = result.slice(0, -1)
index--
}
} else {
result = '0'
}
if (result[result.length - 1] === '.') {
result = result.slice(0, -1)
}
if (result[0] === '.') {
result = '0' + result
}
console.log(result)
return result
}
}
// 任意数减法函数入口
function allSub(a = '0', b = '0') {
const newA = `${a}`
const newB = Number(b) > 0 ? `-${b}`: `${b}`.slice(1)
const statusObj = checkNumber(newA, newB)
if (!statusObj.status) {
return statusObj.data
} else {
const result = allAdd(newA, newB)
return result
}
}
Результаты теста
Пожалуйста, смотрите приведенный выше кодздесь
// 30200003439999.0030200003439999
allAdd('9037499254750994.9037499254750994', '-9007299251310995.9007299251310995')
// 5000000000000000007294977399998.9100199977440001
allAdd('9707494254750996007299232150995.8107499231750996', '-4707494254750996000004254750996.9007299254310995')
// 19994891802101990.9994891802101989
allAdd('9997492547350994.9997492547350994', '9997399254750995.9997399254750995')
// 30200003439999.0030200003439999
allSub('9037499254750994.9037499254750994', '9007299251310995.9007299251310995')
// 18044798506061990.8044798506061989
allSub('9037499254750994.9037499254750994', '-9007299251310995.9007299251310995')
// 17144998486501991.714499848650199
allSub('8107499231750996.8107499231750996', '-9037499254750994.9037499254750994')
Суммировать
Эта статья слишком длинная, поэтому кодовая часть не детализирована (все в комментариях)
В основном анализирует всю идею решения проблемы, захватывает несколько ключевых моментов, чтобы понять
- 1. Расчет между Number.MAX_SAFE_INTEGER и Number.MIN_SAFE_INTEGER является доверенным.
- 2. Задача десятичного сложения и вычитания с точностью с плавающей запятой переносится на целые числа для решения
- 3. При сложении и вычитании больших чисел расчет разбиения (причина пункт 1)
- 4. Разбить на строки по 15 длин в каждой (причина в том, что длина Number.MAX_SAFE_INTEGER равна 16. В любом случае сложение и вычитание удовлетворяют первому пункту, поэтому нет необходимости обращать внимание на вопросы безопасности сложения и вычитание)
- 5. Проблема научной записи, является ли совпадение числом в научной записи, а затем преобразовать его в десятичное, и в то же время выдать предупреждение, поскольку в числе научной записи есть ошибка, расчет будет неточный
В коде есть много мест, которые можно оптимизировать, и завершение довольно неаккуратно (легкий спрей)
Есть ли у вас какие-либо комментарии к изменениям?Добро пожаловать, чтобы предложить
Спасибо за просмотр