0

These functions take radix as an argument:

  • num.toString(radix);
  • parseInt("123", radix);

Is there any other function or method that takes radix (number base), because I would want to use something like parseFloat("1A.B4",radix).

But since I don't imagine there is a lot of them, please name any of them if you know, could be useful, thanks.

Edit: Yes parseFloat("1A.B4",16)should be 26.703125. If you look at , num.toString(radix) it supports bases from 2 to 36

In Firefox console (333.444).toString(36) equals "99.fzf9i56mi"

  • 1
    What is `1A.B4` even meant to mean? – Nick is tired Sep 13 '17 at 22:46
  • 1
    @NickA I believe that would be the hexidecimal equivalent of `26.703125` (26 and 180/256) – Patrick Roberts Sep 13 '17 at 22:53
  • @Pat presumably, need to know exactly what OP is looking for though. As they've specified interest in a hex `parseFloat`. Yet asked for a list of all *"method that takes radix"* – Nick is tired Sep 13 '17 at 22:54
  • 1
    If you just want to parse a hex float you can make a function that does something like this: `parseInt( '1A', 16 ) + parseInt( 'B4', 16 )*Math.pow( 16, -'B4'.length)` – Paul Sep 13 '17 at 23:03

3 Answers3

1

Generalizing @Paulpro's comment into a function, you could redefine parseFloat() like so:

parseFloat = function parseFloat (string, radix = 10) {
  if (radix == 10) {
    return this(string)
  }
  
  const [iString, fString = '0'] = string.split('.')
  const iNumber = parseInt(iString, radix)
  const fNumber = parseInt(fString, radix)
  const fLength = Math.max(fNumber.toString(radix).length, fString.length)
  const sign = Infinity / iNumber === Infinity ? 1 : -1
  
  return iNumber + sign * fNumber / radix ** fLength
}.bind(parseFloat)

console.log(parseFloat('1A.B4', 16))
console.log(parseFloat(0.05.toString(16), 16))
console.log(parseFloat('7', 16))
console.log(parseFloat('-0.8', 16))

I'm not sure if this is what you were looking for, but I hope it helps.

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
  • I think there's a problem if the input has a 0 directly after the `.`, e.g. `parseFloat(0.05.toString(16), 16)` gives 0.8 and not 0.05. – skirtle Sep 13 '17 at 23:42
  • I know this is silly territory, but if you try something like `var number = '0.' + (new Array(100)).join('1234567890');` you'll get a string that's `'0.1234567890123...'` and approximately 1000 digits. The native `parseFloat` can handle this in base 10 but using your current code it would overflow the `Math.pow` for base 16. I'm not sure on specifics but maybe some sort of truncation on the string would fix this? – skirtle Sep 14 '17 at 00:05
  • @skirtle dealing with a ridiculous edge-case like that would unnecessarily bloat the implementation, and also cause loss of precision for more common use-cases, so my recommendation would be to truncate the string to less digits before passing it as input. – Patrick Roberts Sep 14 '17 at 00:07
  • I believe `parseFloat('7', 16)` currently fails, likewise any other number that doesn't have a `.` in it. – skirtle Sep 14 '17 at 00:21
  • Now, that I can address. Fixed. – Patrick Roberts Sep 14 '17 at 00:21
  • Perhaps add support for negative numbers? `parseFloat('-0.8', 16)` currently comes out as positive `0.5`. – skirtle Sep 14 '17 at 00:33
  • Wow, I didn't know you could invoke this() – user3761570 Sep 14 '17 at 02:23
  • @user3761570 if you bind a function to the context, then sure – Patrick Roberts Sep 14 '17 at 02:28
0

This is my attempt at a version of parseFloat that supports a radix. I've tried to avoid using Math.pow because I was concerned about potential problems if the bit after the . was very long.

function parseFloatRadix(num, radix) {
    var parts = num.trim().split('.'),
        integerStr = parts[0] || '0',
        integer = parseInt(integerStr, radix),
        fractionStr = parts[1] || '0',
        index = fractionStr.length - 1,
        fraction = 0,
        sign = integerStr.charAt(0) === '-' ? -1 : 1;

    for ( ; index >= 0 ; --index) {
        fraction += sign * parseInt(fractionStr.charAt(index), radix);
        fraction /= radix;
    }

    return integer + fraction;
}

[
  12.34,
  12345678,
  0.3,
  0.1 + 0.2, // Note this is not 0.3
  0.01,
  0.001,
  0.0001,
  Math.PI,
  0,
  -1,
  -100,
  -1.5,
  -0.5
].forEach(function(num) {
    var hex = num.toString(16),
        binary = num.toString(2);

    console.log(
        num,
        hex,
        binary,
        parseFloatRadix(hex, 16),
        parseFloatRadix(binary, 2)
    );
});
skirtle
  • 27,868
  • 4
  • 42
  • 57
  • FYI `Math.pow( 16, -length )` will give an exact answer for integer `length` up to `268`, since it will be a power of two it is easily stored in JavaScript's floating point number type. Beyond that length the final answer can't be represented in a JavaScript number anyway, so there are no issues using `Math.pow` for this. – Paul Sep 13 '17 at 23:37
  • There could be floating point errors for many-digit numbers in bases that aren't powers of 2, but I don't believe the loop will fix those problems. – Paul Sep 13 '17 at 23:44
  • @Paulpro It wasn't really the accuracy of those extra digits I was concerned about, it was ensuring that they don't bomb out the entire algorithm. If there are 270 digits after the `.` (I know, crazy) my approach should still give a reasonable approximation of the most significant digits, whereas calculating `Math.pow` will just give you `0` or `Infinity` depending on whether you include the `-`. With hindsight it might have been easier just to truncate the input if it's crazy long instead. – skirtle Sep 13 '17 at 23:56
0

I would want to use something like parseFloat("1A.B4", radix)

Sure. While there is no support for radix in parseFloat(), we can easily build our own parseFloatRadix() function like this:

function parseFloatRadix(num, radix) {
  return parseInt(num.replace('.', ''), radix) /
    Math.pow(radix, (num.split('.')[1] || '').length)
}

This stackowerflow answer provides more detail. Demo code below.

function parseFloatRadix(num, radix) {
  return parseInt(num.replace('.', ''), radix) /
      Math.pow(radix, (num.split('.')[1] || '').length)
}

test('1A.B4', 16, 26.703125);
test('99.fzf9i56mi', 36, 333.444);

function test(num, radix, expected){
  let result = parseFloatRadix(num, radix);
  console.log(num + ' (base ' + radix +') --> ' + result + 
    (result === expected ? ' (OK)' : ' (Expected ' + expected + ')'));
}
Tomas Langkaas
  • 4,551
  • 2
  • 19
  • 34