数组(整数或十进制)到数组,数组到数字(整数或小数)而不使用字符串 [英] Number (integer or decimal) to array, array to number (integer or decimal) without using strings

查看:90
本文介绍了数组(整数或十进制)到数组,数组到数字(整数或小数)而不使用字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要求:

将输入整数或小数转换为数组,并将可能包含小数的整数数组转换为数字。

Convert input integer or decimal to an array and convert array of integers which may include a decimal to a number.

限制:

不要使用字符串方法或将输入或输出转换为程序中的字符串(在每个版本的代码组成后都遵循自我限制)。

Do not use string methods or convert input or output to a string during the procedure (a self-imposed restriction followed throughout each version of the code composed).

上下文和用例

BigInt 在某些浏览器中可用,但不是 BigDecimal 。使用JavaScript编程语言可以实现从整数或十进制到数组和数组到整数或十进制的转换。在过程中,输入和输出不需要转换为字符串。

BigInt in available in some browsers, though not a BigDecimal. The conversion from integer or decimal to array and array to integer or decimal should be possible using the JavaScript programming language. The input and output should not need to be converted to a string during the procedure.

能够通过调整 nth 数组索引处的十进制或整数来调整整数或十进制的 nth 数字,尝试直接解决 OEIS A217626 ,例如

Ability to adjust nth digit of an integer or decimal by adjusting decimal or integer at nth index of array, to try to solve OEIS A217626 directly, for example

~~(128.625*9*1.074)//1243
~~(128.625*9*1.144)//1324

其中小数部分可以通过引用数组的索引来操作,然后将数组转换回数字。

where the decimal portion can be manipulated by referencing the index of an array, then converting the array back to a number.

当前规范是WIP,可能被认为难以描述与输入的小数部分的处理相关,特别是在有前导零的情况下。

The current specification is WIP and could be considered challenging to describe relevant to the processing of the decimal portion of input, specifically where there are leading zeros.

Input <----------> Output

-123               [-1,-2,-3]
4.4                [4,0.4]
44.44              [4,4,0.4,4]
-0.01              [-0.01]
123                [1,2,3]
200                [2,0,0]
2.718281828459     [2,0.7,1,8,2,8,1,8,2,8,4,5,8,9]
321.7000000001     [3,2,1,0.7,0,0,0,0,0,0,0,0,1]
809.56             [8,0,9,0.5,6]
1.61803398874989   [1,0.6,1,8,0,3,3,9,8,8,7,4,9,8,9]
1.999              [1,0.9,9,9]
100.01             [1,0,0,0.01]
545454.45          [5,4,5,4,5,4,0.4,5]
-7                 [-7]
-83.782            [-8,-3,-0.7,-8,-2]
1.5                [1,0.5]
100.0001           [1,0,0,0.0001]

本质上,我试图将整数或小数传播到数组。将数字或整数转换为数组的函数必须能够转换为生成函数,才能实现

Essentially, am attempting to spread an integer or decimal to an array. The function which converts a number or integer to an array must be capable of being converted to a generator function, for the ability to achieve

[...Math.E] -> [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9] -> 2.718281828459

将函数设置为 Number.prototype [Symbol.iterator]的值] numberToArray

最新版本的代码(部分代码概念和原始版本的代码基于使用JavaScript获取数字的小数部分; 不使用toString和parseInt方法将int值转换为String ; 将整数转换为数字数组),结果有两个错误来自 arrayToNumber 100.05010000000497 的测试用例输出应为 100.00015 并且 -83.082 应为 -83.782

The most recent version of the code (some of the concepts and original versions of the code were based on questions and answers at Get decimal portion of a number with JavaScript; Converting int value to String without using toString and parseInt method; Convert integer to array of digits), which has two bugs at resulting output of tests cases from arrayToNumber 100.05010000000497 should be 100.00015 and -83.082 should be -83.782.

function numberToArray(n) {

  if (Math.abs(n) == 0 || Math.abs(n) == -0) {
    return [n]
  }

  const r = [];

  let [
    a, int = Number.isInteger(a), d = g = [], e = i = 0
  ] = [ n || this.valueOf()];

  if (!int) {
    let e = ~~a;
    d = a - e;
    do {
      if (d < 1) ++i;
      d *= 10;
    } while (!Number.isInteger(d));
  }

  for (; ~~a; r.unshift(~~(a % 10)), a /= 10);

  if (!int) {
    for (; ~~d; g.unshift(~~(d % 10)), d /= 10);
    g[0] = g[0] * (1 * (10 ** -i))
    r.push(...g);
  }

  return r;

}

function arrayToNumber(a) {
  if ((Math.abs(a[0]) == 0 || Math.abs(a[0]) == -0) 
     && a.length == 1) return a[0];
  const [
    g, r = x => x.length == 1 
                ? x[0] 
                : x.length === 0 
                  ? x 
                  : x.reduce((a, b) => a + b)
    , b = a.find(x => g(x)), p = a.findIndex(x => g(x))
  ] = [x => !Number.isInteger(x)];

  let [i, j] = [b ? p : a.length, -1];

  return a.length === 1 
    ? a[0] 
    : b && p 
      ? r(a.slice(0, p).map(x => i ? x * (10 ** --i) : x)) 
        + (a[p] + (a[p + 1] !== undefined 
          ? r(a.slice(p + 1).map(x => x * (10 ** --j))) 
          : 0)) 
      : r(a.map(x => i ? x * (10 ** --i) : x))
}

let tests = [0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123
            , 2.718281828459, 321.7000000001, 809.56
            , 1.61803398874989, 1.999, 100.01, 545454.45
            , -7, -83.782, 12, 1.50, 100.0001];

let arrays = tests.map(n => [...numberToArray(n)]);

let numbers = arrays.map(n => arrayToNumber(n));

console.log({tests, arrays, numbers});

问题:


  1. 如何修复现有代码中列出的错误?

  2. 在不使用字符串方法或在过程中将输入或输出转换为字符串的限制内,是否可以完全改进或组合代码以满足要求?

  3. 当前的规格是否可以改进了所用术语的清晰度,避免混淆小数的预期输出是什么?


推荐答案

方法 numberToArray()



我一直在你的实施工作,并想到首先分析 numberToArray()方法。首先,我决定创建一个分析十进制数的方法并返回 statistics ,基本上,你从代码的这一部分得到的信息:

Method numberToArray():

I have been working some time on your implementation, and thinked to first analyze the numberToArray() method. To start, I have decided to create a method for analyze a decimal number and return statistics about it, basically, the information you where getting from this part of your code:

if (!int) {
    let e = ~~a;
    d = a - e;
    do {
        if (d < 1) ++i;
        d *= 10;
    } while (!Number.isInteger(d));
}

我所做的方法是下一个(将在 numberToArray())并基本上获取下一个信息:

The method I have made on is the next one (will be used inside numberToArray()) and basically gets the next information:

1)整数部分(小数的 iSection )(作为整数)。

1) Integer section (iSection) of the decimal number (as integer).

2)小数部分( dSection )十进制数(作为整数)。

2) Decimal section (dSection) of the decimal number (as integer).

3)数字点后的数字( dDigits )。

3) Number of digits after the dot (dDigits).

4)前导零的数量在点之后( dZeros )。

4) Number of leading zeros after the dot (dZeros).

function getDecimalStats(dec)
{
    let dDigits = 0, test = dec, factor = 1, dZeros = 0;

    // Store the integer section of the decimal number.

    let iSection = ~~dec;

    // Get the numbers of digits and zeros after the comma.
    
    while (!Number.isInteger(test))
    {
        factor = Math.pow(10, ++dDigits);
        test = dec * factor;
        dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0;
    }

    // Store the decimal section as integer.

    let dSection = test - (iSection * factor);

    // Return an object with all statistics.

    return {iSection, dSection, dZeros, dDigits};
};

console.log(getDecimalStats(10.001));
console.log(getDecimalStats(-210.1));
console.log(getDecimalStats(-0.00001));

.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

当然,如果你不喜欢,你可以将相同的逻辑直接放在 numberToArray()方法中。因此,在完成上一个函数之后,我对代码进行了一些重组并添加了一些注释来帮助我理解你在做什么。最后,在调整了代码之后,我发现错误的数组映射主要是因为使用float数运算时的算术精度。在调查了一些关于这个问题的时间之后,我找到了一个基于数学校正因子的解决方案(在应用代码时对其进行了评论)。总而言之,直到这个时候,我已经接受了 numberToArray()方法的下一个解决方案。

Of course, if you dislike, you can put this same logic directly inside numberToArray() method. So, after making the previous function, I have done some reorganization on your code and added some commentaries to helps me understand what you where doing. Finally, and after adapted your code, I have found that the wrong mapping to the arrays was mostly because the arithmetic precision when operating with float number. After investigate some time about this problem, I found a solution that is based using a mathematical correction factor (it is commented on the code when it is applied). All in all, and until this time, I have come with the next solution to the numberToArray() method.

function getDecimalStats(dec)
{
    let dDigits = 0, test = dec, factor = 1, dZeros = 0;

    // Store the integer section of the decimal number.

    let iSection = ~~dec;

    // Get the numbers of digits and zeros after the comma.
    
    while (!Number.isInteger(test))
    {
        factor = Math.pow(10, ++dDigits);
        test = dec * factor;
        dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0;
    }

    // Store the decimal section as integer.

    let dSection = test - (iSection * factor);

    // Return an object with all statistics.

    return {iSection, dSection, dZeros, dDigits};
};

function numberToArray(n)
{
    let r = [];

    if (Math.abs(n) == 0)
        return [n];

    let [a, int = Number.isInteger(a), g = []] = [n || this.valueOf()];

    // Get the stats of the decimal number.

    let {dSection, dZeros} = getDecimalStats(a);

    // Push the integer part on the array.

    for (; ~~a; r.unshift(~~(a % 10)), a /= 10);

    // Push the decimal part on the array.

    if (!int)
    {
        // Push decimal digits on temporal array "g".
        for (; ~~dSection; g.unshift(~~(dSection % 10)), dSection /= 10);

        // Define the correction factor for the next operation.
        let cf = 10 ** (++dZeros);

        // Map g[0] to a decimal number and push elements on the array.
        g[0] = (g[0] * cf) * ((10 ** -dZeros) * cf) / (cf * cf);
        r.push(...g);
    }

    return r;
}

let tests = [
0, 200, 100.00015, -123, 4.4, 44.44, -0.01, 123,
2.718281828459, 321.7000000001, 809.56,
1.61803398874989, 1.999, 100.01, 545454.45,
-7, -83.782, 12, 1.50, 100.0001
];

let arrays = tests.map(n => [...numberToArray(n)]);
console.log({tests, arrays});

.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

对于这个我决定自己去(实际上忽略了你当前的逻辑)。下一种方法将使用前面提到的 getDecimalStats(),主要是 Array :: reduce()

For this one I decided to go on my own (actually ignoring your current logic). The next approach will use the previously mentioned getDecimalStats() and mainly the Array::reduce():

function getDecimalStats(dec)
{
    let dDigits = 0, test = dec, factor = 1, dZeros = 0;

    // Store the integer section of the decimal number.

    let iSection = ~~dec;

    // Get the numbers of digits and zeros after the comma.
    
    while (!Number.isInteger(test))
    {
        factor = Math.pow(10, ++dDigits);
        test = dec * factor;
        dZeros += Math.abs(test - (iSection * factor)) < 1 ? 1 : 0;
    }

    // Store the decimal section as integer.

    let dSection = test - (iSection * factor);

    // Return an object with all statistics.

    return {iSection, dSection, dZeros, dDigits};
};

function arrayToNumber(a)
{
    // Get the index of the first decimal number.

    let firstDecIdx = a.findIndex(
        x => Math.abs(x) > 0 && Math.abs(x) < 1
    );

    // Get stats about the previous decimal number.

    let {dZeros} = getDecimalStats(firstDecIdx >= 0 ? a[firstDecIdx] : 0);

    // Normalize firstDecIdx.

    firstDecIdx = firstDecIdx < 0 ? a.length : firstDecIdx;

    // Reduce the array to get the number.
    
    let number = a.reduce(
        ({num, dIdx, dPow}, n, i) =>
        {
            // Define the correction factor.
            let cf = 10 ** (dPow + i - dIdx);

            if (i < dIdx)
               num += n * (10 ** (dIdx - i - 1));
            else if (i === dIdx)
               num = ((num * cf) + (n * cf)) / cf;
            else
               num = ((num * cf) + n) / cf;

            return {num, dIdx, dPow};
        },
        {num: 0, dIdx: firstDecIdx, dPow: ++dZeros}
    );

    return number.num;
}

let tests = [
    [0],
    [2, 0, 0],
    [1, 0, 0, 0.0001, 5],
    [-1, -2, -3],
    [4, 0.4],
    [4, 4, 0.4, 4],
    [-0.01],
    [1, 2, 3],
    [2, 0.7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9],
    [3, 2, 1, 0.7, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [8, 0, 9, 0.5, 6],
    [1, 0.6, 1, 8, 0, 3, 3, 9, 8, 8, 7, 4, 9, 8, 9],
    [1, 0.9, 9, 9],
    [1, 0, 0, 0.01],
    [5, 4, 5, 4, 5, 4, 0.4, 5, 0],
    [-7],
    [-8,-3, -0.7, -8, -2],
    [1, 2],
    [1, 0.5],
    [1, 0, 0, 0.0001]
];

let numbers = tests.map(n => arrayToNumber(n));
console.log(numbers);

.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

最后,我希望你能重视我的价值努力,显然我的解决方案可以有很多改进(因此,欢迎任何建议)。例如,目前没有或几乎没有安全检查。

Finally, I hope you can value my efforts, and obviously there can be a lot of improvements to my solution (so, any recommendation is welcome). For example, there are currently none or few checks for safety.

这篇关于数组(整数或十进制)到数组,数组到数字(整数或小数)而不使用字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆