# Changing base number for float's exponent in Go?

How do you change the base of float’s exponent in Go from base10 to base5/8/16 or any base number system? Data type is `float32/float64` of course.

Given that the mathematical equations is:

``````B^y = 10^x
y = x*logB(10)  --- [1]

∴,
base5:  y = x*log5(10)
base8:  y = x*log8(10)
base16: y = x*log16(10)
``````
1 Like

In a literal you mean? I doubt you can change that.

2 Likes

Yes. It’s for changing the entire float number (default is base10) to baseX, in case the number is huge and represented in exponent form.

1 Like

`math` package has a `log2` function, have you tried with the following mathematical model with rounding to the nearest number?

``````B^y = 10^x
y = x*logB(10)  --- [1]

From [1],
y = ‖x*(log2(10) / log2(B))‖
y = ‖x*c, c = log2(10) / log2(B)‖    --- [2]

∴,
base2,
y = x*c, c = log2(10) / log2(2)
y = x*c, c = log2(10)
y = ‖x*log2(10)‖

base5,
y = x*log5(10)
y = ‖x*c, c = log2(10) / log2(5)‖

base8,
y = x*log8(10)
y = x*c, c = log2(10) / log2(8)
y = ‖x*c, c = log2(10) / 3‖

base16,
y = x*log16(10)
y = x*c, c = log2(10) / log2(16)
y = ‖x*c, c = log2(10) / 4‖
``````

There are 2 calculation stages:

1. calculate the `c` constant based on the target base `B`.
2. calculate the `y` with the given `x`.

The division op’ cost is quite expensive for calculating `c`. A pre-built lookup table is one way to mitigate all divisions to multiplication.

On code, it should looks something like this (untested):

``````func ExponentToBase(base uint, x float64) float64 {
var c float64

switch {
case x == 0:
return 0 // indice 0 is always equal to 0 regardless base
case base == 0:
panic("base cannot be 0")// base cannot be 0
case base == 1:
panic("base cannot be 1") // log2(1) is 0 and that means log2(10) is divided by 0
case base == 2:
c = ... // lookup pre-calculated log2(10)
case base == 3:
c = ... // lookup
...
case base == 8:
c = ... // lookup pre-calculated log2(10) / 3
...
case base == 16:
c = ... // lookup pre-calculated log2(10) / 4
...
default:
c = math.log2(10) / math.log2(float64(base)) // calculate constant as last resort
}
return math.Round(x*c)
}
``````
1 Like

Go 1.13 has base 16 (hex) float literals.

A hexadecimal floating-point literal consists of a `0x` or `0X` prefix, an integer part (hexadecimal digits), a radix point, a fractional part (hexadecimal digits), and an exponent part ( `p` or `P` followed by an optional sign and decimal digits). One of the integer part or the fractional part may be elided; the radix point may be elided as well, but the exponent part is required. (This syntax matches the one given in IEEE 754-2008 §5.12.3.) An exponent value exp scales the mantissa (integer and fractional part) by 2exp.

2 Likes

Thanks @calmh. No worries about literal parsing. It is the computational world that is worrying for me.

I tested on my side using the ISO6093NR3 notation, looks good so far and you’re right, the division computation is very costly.

``````func ExponentToBase(base uint, x float64) uint64 {
var c float64

switch {
case x == 0:
return 1 // x^0 = y^0 = 1
case base == 0:
panic("base cannot be 0")// base cannot be 0
case base == 1:
panic("base cannot be 1") // log2(1) = 0. ∴, log2(10) / 0
case base == 2:
c = 3.321928094887362 //  log2(10)
case base == 8:
c = 1.1073093649624541 // log2(10) / 3
case base == 10:
return uint64(x)
case base == 16:
c = 0.8304820237218405 // log2(10) / 4
default:
c = math.log2(10) / math.log2(float64(base)) // calculate
}
return uint64(math.Round(x*c))
}
``````

I also created the anti-log using the same pattern. However, it was `c'` is now `1/c`

``````func BaseToExponent(base uint, x float64) uint64 {
var c float64

switch {
case x == 0:
return 1 // x^0 = y^0 = 1
case base == 0:
panic("base cannot be 0")// base cannot be 0
case base == 1:
panic("base cannot be 1") // log2(1) = 0. ∴, log2(10) / 0
case base == 2:
c = 0.3010299956639812 //  1 / log2(10)
case base == 8:
c = 0.9030899869919435 // 3 / log2(10)
case base == 10:
return uint64(x)
case base == 16:
c = 1.2041199826559248 // 4 / log2(10)
default:
c = math.log2(float64(base)) / math.log2(10)  // calculate
}
return uint64(math.Round(x*c))
}
``````

Looks good so far. Will work on reducing the division cost.

1 Like

I’ll close this topic since we got an answer and reducing division cost is an optimization that can be done later. All good and thank you!

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.