Как преобразовать числовое значение в нормированную двойную точность в памяти и наоборот в R? - PullRequest
1 голос
/ 24 мая 2019

Моя главная цель - написать функцию, которая преобразует:

  • (десятичное) числовое значение с нормализованной двойной точностью в памяти
  • нормализованная двойная точность в памяти до (десятичного) числового значения

т. Е.

from10toNdp(86.125) # 0100000001010101100010000000000000000000000000000000000000000000 (sign|exponent|significand)

fromNdpTo10(0100000001010101100010000000000000000000000000000000000000000000) # 86.125

На пути к созданию from10toNdp и fromNdpTo10 я проделал следующее.

Я написал несколько помощников:

from10to2 <- function(decimalnumber) {
  binaryvector <- rep(0, 1 + floor(log(decimalnumber, 2)))
  while (decimalnumber >= 2) {
    power <- floor(log(decimalnumber, 2))
    binaryvector[1 + power] <- 1
    decimalnumber <- decimalnumber - 2^power  }
  binaryvector[1] <- decimalnumber %% 2
  paste(rev(binaryvector), collapse = "")}
from10to2(8) # "1000"

Функция from10to2 отлично работает для целых чисел, меньших 2 ^ 53 = 9.007199e15 (т. Е. Она работает и для целых чисел, хранящихся также как double; работает для значений, превышающих 2147483647); для чисел больше 2 ^ 53 он начинает терять цифры.

ПРИМЕР 1: Преобразовать 0,3-64-разрядное нормализованное число двойной точности:
Знак: 0: позитивный; 1: отрицательный

sprintf("%a", 0.3) # ("0x1.3333333333333p-2")16
library(BMS)
BMS::hex2bin("3333333333333") # (0011001100110011001100110011001100110011001100110011)2=significand=(3333333333333)16

Так как последние три «p-2» и «BiasedExponent = RealExponent + 1023bias» выходных данных sprintf (смещение: 2 ^ (11-1) -1 = 1023), показатель степени (11 бит) равен -2 + 1023 = 1021

from10to2(1021) # ("01111111101")2

Двойная точность хранения:
0 | 01111111101 | 0011001100110011001100110011001100110011001100110011
знак | показатель | мантисса

ПРИМЕР2: Преобразовать -2,94 в 64-разрядное нормализованное число с двойной точностью:
Знак: 0: позитивный; 1: отрицательный

sprintf("%a", -2.94) # "-0x1.7851eb851eb85p+1"
library(BMS)
BMS::hex2bin("7851eb851eb85") # (0111100001010001111010111000010100011110101110000101)2=significand=(7851eb851eb85)16

Так как последние три «p + 1» и «BiasedExponent = RealExponent + 1023bias» выходных данных sprintf (смещение: 2 ^ (11-1) -1 = 1023), показатель степени (11 бит) равен 1 + 1023 = 1024.

from10to2(1024) # ("10000000000")2

Двойная точность хранения:
1 | 10000000000 | 0111100001010001111010111000010100011110101110000101
знак | показатель | мантисса

ПРИМЕР3: Преобразовать 86.125 в 64-разрядное нормализованное число с двойной точностью:
Знак: 0: позитивный; 1: отрицательный

sprintf("%a", 86.125) # "0x1.588p+6"
library(BMS)
BMS::hex2bin("588") # (010110001000)2=significand=(588)16

Так как последние три «p + 6» и «BiasedExponent = RealExponent + 1023bias» выходных данных sprintf (смещение: 2 ^ (11-1) -1 = 1023), показатель степени (11 бит) равен 6 + 1023 = 1029.

from10to2(1029) # ("10000000101")2

Двойная точность хранения:
0 | 10000000101 | 010110001000 (но это не 64-битный, а 1 + 11 + 12 = 24-битный!)
знак | показатель | мантисса. Истинная 64-битная двойная точность должна быть:
0 | 10000000101 | 0101100010000000000000000000000000000000000000000000.
Таким образом, этот метод не может найти последние 40 нулей, но может правильно найти первые 24 бита.

Онлайн конвертеры:

  1. https://www.exploringbinary.com/floating-point-converter/
    "Raw Binary (поле знака | поле экспоненты | поле значимости и поле) Double:"
  2. http://www.binaryconvert.com/convert_double.html

Моя методика (которая работает для 0,3 и -2,94) неожиданно перестает работать для 86,125 и не выдает 64-разрядную версию.

Почему техника останавливается на 86,125?

Уже есть способ конвертировать:

  • (десятичное) числовое значение с нормализованной двойной точностью в памяти
  • нормализованная двойная точность в памяти до (десятичного) числового значения?

(Надеюсь, я не открываю Америку с нуля)

Любая помощь очень ценится.

1 Ответ

1 голос
/ 25 мая 2019
library(BMS)

from10toNdp <- function(my10baseNumber) {
out <- list()

# Handle special cases (0, Inf, -Inf)
if (my10baseNumber %in% c(0,Inf,-Inf)) {
if (my10baseNumber==0)    { out <- "0000000000000000000000000000000000000000000000000000000000000000" }
if (my10baseNumber==Inf)  { out <- "0111111111110000000000000000000000000000000000000000000000000000" }
if (my10baseNumber==-Inf) { out <- "1111111111110000000000000000000000000000000000000000000000000000" }
} else {

signBit <- 0 # assign initial value

from10to2 <- function(deciNumber) {
  binaryVector <- rep(0, 1 + floor(log(deciNumber, 2)))
  while (deciNumber >= 2) {
    theExpo <- floor(log(deciNumber, 2))
    binaryVector[1 + theExpo] <- 1
    deciNumber <- deciNumber - 2^theExpo  }
  binaryVector[1] <- deciNumber %% 2
  paste(rev(binaryVector), collapse = "")}

#Sign bit
if (my10baseNumber<0) { signBit <- 1 
} else { signBit <- 0 }

# Biased Exponent
BiasedExponent <- strsplit(from10to2(as.numeric(substr(sprintf("%a", my10baseNumber), which(strsplit( sprintf("%a", my10baseNumber), "")[[1]]=="p")+1, length( strsplit( sprintf("%a", my10baseNumber), "")[[1]]))) + 1023), "")[[1]] 
BiasedExponent <- paste(BiasedExponent, collapse='')
if (nchar(BiasedExponent)<11) {BiasedExponent <-  paste(c(  rep(0,11-nchar(BiasedExponent)), BiasedExponent),collapse='')    }

# Significand
significand <- BMS::hex2bin(substr( sprintf("%a", my10baseNumber) , which(strsplit( sprintf("%a", my10baseNumber), "")[[1]]=="x")+3, which(strsplit( sprintf("%a", my10baseNumber), "")[[1]]=="p")-1))

significand <- paste(significand, collapse='')
if (nchar(significand)<52) {significand <-  paste(c( significand,rep(0,52-nchar(significand))),collapse='')    }

out <- paste(c(signBit, BiasedExponent, significand), collapse='')
}

out
}


from10toNdp(0.3)
# "0011111111010011001100110011001100110011001100110011001100110011"
from10toNdp(-2.94)
# "1100000000000111100001010001111010111000010100011110101110000101"
from10toNdp(86.125)
# "0100000001010101100010000000000000000000000000000000000000000000"
from10toNdp(-589546.684259)
# "1100000100100001111111011101010101011110010101110011001000010110"

from10toNdp(0)
# "0000000000000000000000000000000000000000000000000000000000000000"
from10toNdp(Inf)
# "0111111111110000000000000000000000000000000000000000000000000000"
from10toNdp(-Inf)
# "1111111111110000000000000000000000000000000000000000000000000000"
...