2014-06-06 55 views
4

我目前產生一個JavaScript驅動數學包,其重點四捨五入各種顯著數字(SF)但我已經運行成我掙扎的一個問題解決。舍入到有效數字 - 缺少零點

更多關於這個問題後,但首先給你一些背景。

該計劃的目的是選擇一個完全隨機數在一定範圍內,然後自動計算出該號碼的相關顯著數字;例如:

隨機數:0.097027S.Fs:9, 7, 0, 2, 7


這裏是什麼,我產生了給你的直觀表示截圖:

enter image description here

正如您所看到的,一旦用戶選擇了他們的號碼,他們就有機會點擊四個獨立的'SF'按鈕查看分別呈現給1,2,3和4個S.F的隨機數。

對於每個SF(1-4)隨機數爲捨去圍捕四捨五入X SF和下方的標尺給用戶一個更視覺呈現,以顯示爲什麼SF值已被程序選擇。

我已經爲此寫了絕大多數的代碼並進行了測試,到目前爲止數字已經出來了,我期待他們。 Well ...

在我給出的例子中(0.097027);正如你在我所包含的圖像上看到的那樣,4 S.F的數據是絕對正確的並且準確輸出。

當我點擊到3 SF按鈕,我希望看到以下內容:

隨機數:0.0970273 SF圍捕/ DOWN/OFF:0.0970

但是,我實際得到的是:

隨機數:0.0970273 S.F圓形向上/向下/關閉:0.097

該程序未顯示附加零。這是我的程序中以數字結尾的一個數字的完美示例,在這種情況下,零是非常重要的,必須顯示。


數據通常是正確的,但在正確的時間輸出顯着的零似乎存在問題。我研究了toFixed(x)方法,如果我分配toFixed(4),我會得到正確的所需輸出,但是因爲我的數字是每次隨機生成的,所以它們的範圍可以從5個數字的長度(例如, 89.404高達> 10,例如`0.000020615。

因此,看起來方法需要是靈活/動態的,例如,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); 
}; 

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

更新:

我還在繼續,試圖找到一個解決方案這個問題和我最近採取的一種方法是將我的隨機生成的數字轉換爲可搜索的字符串變量,然後使用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' 

我已經這才得以進一步瞄準我的搜索,以確定我的第一個顯著數量是否在它之後立即位數任何「問題」零。

如果有,然後我設置一個布爾變量爲'true',然後在一個單獨的函數中創建我的舍入/關閉/向上數字的更多文本字符串,所以我可以物理地選擇添加'0 '到現有數字字符的末尾。

這種方法對我個人來說在孤立的情況下工作,但隨機數字長度從5-12位長,但仍不能處理所有情況。

也許我需要創建一個動態的toFixed(i)函數?任何想法都會受到歡迎。

回答

0

我又走了,我想我現在已經終於解決了我最初的問題。

我的部分關於何時使用toFixedtoPrecision存在一定程度的混淆。我以前曾嘗試將我的四捨五入,關閉和關閉號碼轉換爲字符串,然後通過搜索每個這些查找小數點("."),然後計算出尾隨數量的數量,以便生成正確的toFixed點。

但是,由於我的隨機數可能高達12位數,所以這是非常受歡迎的,所以我現在所做的就是正確利用toPrecision。因爲我已經使用了相應的toPrecision點的每個「SF按鈕」(1-4),例如用於SF1:

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

    //Add The new scale data (Rounded Down) 
    downTextBlock = document.getElementById('down'); 
    document.getElementById("down").innerHTML = String(downArray[i].toPrecision(1)); 

    //Add The new scale data (Rounded Up) 
    upTextBlock = document.getElementById('up'); 
    document.getElementById("up").innerHTML = String(upArray[i].toPrecision(1)); 

現在,這是給我準確的結果,在每一個場合,但仍有一個障礙左跳。偶爾我會達到一個隨機場景,其中科學記數法必須包括在我輸出的答案中,例如, 21819舍入爲1 SF,將在2e+4而不是20000中讀出。

爲了解決這個問題,我把我的上,下,四捨五入的數字設置成可搜索的字符串,然後通過這些查找來查找任何非法/科學字符[a-z]。如果我發現有任何,我執行一個稍微不同的版本,我的輸出,由parseFloat使用,這剝奪了科學記數法,並顯示出正確的數字:

//Convert Up, Down and Rounded into Strings based on their precision 
     var upString = String(upArray[i].toPrecision(1)); 
     var downString = String(downArray[i].toPrecision(1)); 
     var roundedString = String(roundedArray[i].toPrecision(1)); 
     //Set up a regexp to search for characters [a-z], i.e. non-numeric 
     var regexp = /[a-z]/g; 
     //Search the up, down and rounded strings for non-numeric characters 
     var upResult = upString.match(regexp); 
     var downResult = downString.match(regexp); 
     var roundedResult = roundedString.match(regexp); 
     //If any of these strings contain a letter (non-numeric) we need to add in parseFloat to strip away the scientific notation included. 
     var containsChar = false; 

     if (upResult != null || downResult != null || roundedResult != null) 

      { 
       containsChar = true; 
       //alert("There is SN included here"); 
      } 

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

     if (containsChar == true) 

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

      //Add The new scale data (Rounded Down) 
      downTextBlock = document.getElementById('down'); 
      document.getElementById("down").innerHTML = String(parseFloat(downArray[i].toPrecision(1))); 

      //Add The new scale data (Rounded Up) 
      upTextBlock = document.getElementById('up'); 
      document.getElementById("up").innerHTML = String(parseFloat(upArray[i].toPrecision(1))); 
     } 

已經測試了廣泛的它似乎希望合作。

3

而不是玩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); 
    } 
}