四舍五入到有效数字 - 缺少零

Joe*_*oel 4 javascript math

我目前正在制作一个 JavaScript 驱动的数学包,其重点是舍入到各种有效数字 (SF),但我遇到了一个正在努力解决的问题。

稍后会详细讨论这个问题,但首先为您提供一些背景知识。

该程序的目的是在给定范围内选择一个完全随机的数字,然后自动计算出该数字的相关有效数字;例如:

随机数: 0.097027 S.Fs: 9, 7, 0, 2, 7


这是我制作的屏幕截图,为您提供直观的表示:

在此输入图像描述

如您所见,一旦用户选择了号码,他们就有机会单击四个单独的“SF”按钮来查看分别呈现给 1、2、3 和 4 个 S.F 的随机号码。

对于每个 SF (1-4),随机数向下舍入、向上舍入并四舍五入到X SF,下面的比例为用户提供了更直观的呈现,以显示程序选择 SF 值的原因。

我已经为此编写了绝大多数代码并对其进行了测试,到目前为止,数字正如我所期望的那样。嗯,差不多...

在我给出的例子中(0.097027);正如您在我包含的图像中看到的,4 SF 的数据绝对正确并且输出准确。

当我单击3 SF按钮时,我希望看到以下内容:

随机数: 0.097027 3 SF 向上/向下/关闭: 0.0970

然而,我实际得到的是:

随机数: 0.097027 3 SF 向上/向下/关闭: 0.097

该程序尚未显示附加零。这是我的程序中以零结尾的数字的完美示例,在这种情况下,零非常重要并且必须显示。


数据通常是正确的,但在正确的时间输出有效的零似乎存在问题。我研究了该toFixed(x)方法,如果我分配,toFixed(4)我会得到正确的所需输出,但因为我的数字每次都是随机生成的,所以它们的长度范围可以是 5 位数字,例如89.404最多 > 10,例如 `0.000020615。

所以看起来该 toFixed 方法需要灵活/动态,例如 toFixed(n) 预先运行一个函数来确定到底需要多少个尾随零?

以下是我当前解决方案的一些关键摘录,供您考虑:

function generateNum() {

do {
        genNumber = Math.random() * Math.pow (10, randomRange(-5, 5));

        //Round
        genNumber = roundToNSF(genNumber, 5, 0);

        // This number must contain >1 digit which is 1 to 9 inclusive otherwise we may have e.g. 100. Rounding 100
    } 

while (!countNonZero(genNumber) || genNumber < 1E-05 || genNumber == 0);

    //Round
    genNumber = roundToNSF(genNumber, 5, 0);


    genNumber = String(genNumber);
    genNumber = Number(genNumber);
}

//----------------------------------------------------------------------------

function randomRange(min, max) {

/**
 * Returns a random integer between min (inclusive) and max (inclusive)
 * Using Math.round() will give you a non-uniform distribution!
 */

return Math.floor(Math.random() * (max - min + 1)) + min;

} 

//---------------------------------------------------------------------------
//Click SF3 Button to reveal the data
function showSF3() {

//Remove any CSS properties on the buttons from previous use
removeButtonCSS();

document.getElementById('SFRounded').style.display = "block";
document.getElementById('scale').style.display = "block";
document.getElementById("SF3").className = document.getElementById("SF3").className + "buttonClick";  // this removes the blue border class

//Clear text
deleteRounded();
deleteScale();

//Run calculation
calculateAnswer();

//alert(genNumber.toFixed(4));

for (i = 3; i < 4; i++)

    {
         //Add The new data
         sfRoundedTextBlock = document.getElementById('SFRounded');

         //alert(downArray[i].toFixed(4));

         //Data output to HTML.

         sfRoundedTextBlock.innerHTML = sfRoundedTextBlock.innerHTML + '<p><strong>Number: </strong></br>' + String(genNumber) + 
         '</br>' + '<strong>Rounded down to ' + i + ' SF:</br></strong>' + downArray[i] + '</br>' + 
         '<strong>Rounded up to ' + i + ' SF:</br></strong>' + upArray[i] + '</br><strong>Rounded off to ' + i + ' SF:</br></strong>' 
         + roundedArray[i] + '</br>' + '(See the scale below for why we choose <strong>' + roundedArray[i] + '</strong> as the rounded off value.)</p>';

    }

}

//----------------------------------------------------------------------

var roundedArray = [];
var upArray = [];
var downArray = [];
var temp;

function calculateAnswer() {
//Clear Arrays
roundedArray = [];
upArray = [];
downArray = [];

// Work out the answer:
for (i = 0; i < 4; i++) {

    var nSF = i + 1;
    // Round OFF ...
    temp = roundToNSF(genNumber, nSF, 0);
    // We actually have to do this twice ...
    roundedArray[nSF] = roundToNSF(temp, nSF, 0);

    // Round UP ...
    upArray[nSF] = roundToNSF(genNumber, nSF, 1);

    // Round DOWN ...
    downArray[nSF] = roundToNSF(genNumber, nSF, -1);
    // e.g. x = 0.0098 rounded to 1SF is 0.010 initially (take the log of 0.0098 and try it!).
};  
};


//-------------------------------------------------------------------------

//Globals
var aNumber;
var digits;
var way;

function roundToNSF(aNumber, digits, way){
// Round a number to n significant figures (can use roundToNDP provided we know how many decimal places):
    if (way == undefined) { way = 0; }; // default is round off

if (aNumber !=0) {

    if (aNumber > 0)
        { 
            z = log10(aNumber); 
        } 
        else 
            { 
                z = log10(-aNumber); 
            };

    z = Math.floor(z);

    var nDP = digits - z - 1; // Rounding to nDP decimal places is equivalent to rounding to digits significant figures ...

    var roundedNumber = roundToNDP(aNumber, nDP, way);

} 
else {

    roundedNumber = aNumber; // Number is zero ...
};

return Number(roundedNumber);
};

//---------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

更新:

我仍在继续尝试找到这个问题的解决方案,我最近采取的方法是将随机生成的数字转换为可搜索的字符串变量,然后使用命令indexOf(".")查找小数点(dp)的位置的位置。

然后我搜索了我的数字,从 dp 的位置开始,找到第一个重要的非零数字 [1-9]。

var genNumber =  0.097027;
var rString = String(genNumber);
var positionofDP = rString.indexOf(".");
var regexp = /[1-9]/;
var positionofNonZero = Number(rString.search(regexp, positionofDP));  // Output would be '5'
Run Code Online (Sandbox Code Playgroud)

然后,我能够进一步确定我的搜索目标,以确定我的第一个有效数字后面的直接数字中是否有任何“有问题”的零。

如果有的话,我将一个布尔变量设置为“true”,然后在一个单独的函数中创建进一步的四舍五入/向下/向上数字的文本字符串,这样我就可以物理上选择在现有数字字符的末尾。

这种方法在个别情况下确实对我有用,但由于我的随机数长度范围为 5-12 位数字,它仍然无法处理所有情况。

也许我需要创建一个动态toFixed(i)函数?任何想法都会受到极大的欢迎。

lco*_*rre 5

您可以直接管理字符串,而不是使用 Int 上的固定点。

这是一个小小提琴的链接:http://jsfiddle.net/5rw5G/4/

这并不是为了完全/准确地解决您的问题,但可能会帮助您找到另一种解决方案。

function getRoundedSFs(num, SFCount) {    
    // Match every "leading zeros" before and after the .
    var matches = num.toString().match(/^-?(0+)\.(0*)/);

    // starting with "0."
    if (matches) { 
        var firstIndex = matches[0].length;
        var prefix = matches[0];

        sf = Number(num.toString().substring(firstIndex, firstIndex + SFCount + 1));
        sf = Math.round(sf / 10);
        sf = prefix + sf.toString();
        return Number(sf).toFixed(matches[2].length+SFCount);
    } 

    // starting with something else like -5.574487436097115
    else { 
        matches = num.toString().match(/^(-?(\d+))\.(\d+)/);
        var decimalShift = SFCount - matches[2].length;        
        var rounded = Math.round(num * Math.pow(10, decimalShift));       
        rounded /= Math.pow(10, decimalShift);
        return rounded.toFixed(decimalShift);
    }
}
Run Code Online (Sandbox Code Playgroud)