From: Dr J R Stockton on 27 Jul 2010 16:44 In comp.lang.javascript message <yxMdqJVxyOPMFwXk(a)invalid.uk.co.demon.me rlyn.invalid>, Tue, 13 Jul 2010 23:46:09, Dr J R Stockton <reply1028(a)merlyn.demon.co.uk> posted: >Recent threads about errors in implementations of Number.toString(Radix) >and the lack of an ECMA parseFloat(String, Radix) are now probably lost >to most of you among the spam; hence this new one. ISTM time to show this, from <URL:http://www.merlyn.demon.co.uk/js-exact.htm>, where it is tested. Essentially, it is parseFloat, but with a second argument for the radix, and not handling floating-point strings (i.e. 123.456, but not 1.23456e2) (for those, see above on that page) (for algorithm, see page). Quicker methods have been presented, but they all seem to include inexact operations. A single inexact operation may always give the best available result; but if more than one are used, getting the best available result probably cannot be guaranteed. "Completely accurate" means that the Number given will always be the IEEE Double nearest in value to the number represented by the input, rounded up if there are two equal nearest. Note that it can be meaningfully tested in Base 10, since that gets no special treatment. function refParseFixed(IN, Rdx) { var Sign = +1, J = 0, Tmp, Scale // This is slow; it is intended to be completely accurate. var Digits = "0123456789abcdefghijklmnopqrstuvwxyz" Tmp = IN.charAt(0) // Handle possible sign if (Tmp == "-") { J++ ; Sign = -1 } else if (Tmp == "+") J++ // Split IN into 2 arrays, Int & Frc, of 0 <= Number < Rdx var Num = Int = [], Frc = [], K = IN.length, Cy = true, Bin = [] while (J < K) { Tmp = IN.charAt(J++) // read char from string if (Tmp == "." && Num == Int) { Num = Frc ; continue } Tmp = Digits.indexOf(Tmp.toLowerCase()) // char to Number if (Tmp < 0 || Tmp >= Rdx) break // incorrect digit ends if (Tmp > 0) Cy = false // so not all zero Num.push(Tmp) } // arrays now hold digit Numbers if (Cy) return Sign * 0 // Zero (otherwise loops forever) // Process integer part; repeatedly halve it to get binary bits : while (J = Int.length) { // not == for (K=0, Cy=0 ; K<J ; K++) { // halving loop Tmp = Cy * Rdx + Int[K] ; Cy = Tmp % 2 ; Int[K] = (Tmp-Cy)/2 } Bin.push(Cy) while (Int[0] == 0) Int.shift() } Bin.reverse() while (Bin.length && Bin[0]==0) Bin.shift() // Omit any leading 0s J = Bin.length - 54 ; Scale = 0.5 ; while (--J >= 0) Scale /= 2 // Do fractional part; repeatedly double it to get binary bits : while (Bin.length < 54) { Cy = 0 ; K = Frc.length while (K--) { // doubling loop Tmp = Frc[K]*2 + Cy ; Cy = +(Tmp>=Rdx) ; Frc[K] = Tmp % Rdx } if (Bin.length || Cy == 1) Bin.push(Cy) Scale *= 2 } Bin[52] += Bin[53] // Rounding: now use Bin[0..52] // Evaluate Bin[0..52] into Num, scale it, add the Sign : for (J = 0, Num = 0 ; J < 53 ; J++) { Num *= 2 ; Num += Bin[J] } return Sign * Num / Scale } // end refParseFixed -- (c) John Stockton, near London. *@merlyn.demon.co.uk/?.?.Stockton(a)physics.org Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links. Correct <= 4-line sig. separator as above, a line precisely "-- " (RFC5536/7) Do not Mail News to me. Before a reply, quote with ">" or "> " (RFC5536/7)
First
|
Prev
|
Pages: 1 2 Prev: Discount Lacoste Coat Next: FAQ Topic - How do I make a suggestion? (2010-07-14) |