在 R 中将浮点数或二进制数表示为 32 位有符号整数

Iso*_*Bar 5 floating-point integer r ieee-754

我接到了用 R 为 AR.Drone 2.0 编写 API 的任务。我知道这可能不是最明智的语言选择,因为有用 Python 和 JS 编写的经过验证的良好 API,但我还是接受了挑战。

在我不得不格式化发送给无人机的 AT* 命令字符串之前,我做得很好。这些命令接受的参数可以是带引号的字符串、按原样发送的整数,也可以是必须表示为 32 位有符号整数的二进制和浮点数(-1 到 1 之间的单精度 IEEE754 浮点值)。

我能够通过 2 个在线转换器进行转换,首先从浮点数或二进制转换为十六进制,然后将十六进制转换为 32 位有符号整数,因此我对最常见的值进行了基本转换;但是,我想使用 R 的内置函数或添加的包来进行转换。Python 的struct函数可以轻松处理这个问题:

import struct
print "Float , Signed Integer"
for i in range(-10,10):
    z = float(i)/10
    Y = struct.unpack('i', struct.pack('f', z))[0]
    print "%.1f , %d" % (z,Y)

land = 0b10001010101000000000000000000
take_off = land + 0b1000000000
print "Binary representation is simple as just using the %d format:"
print "Land code: %d, Take off code: %d" % (land, take_off)
Run Code Online (Sandbox Code Playgroud)

此代码将产生以下输出:

Float , Signed Integer
-1.0 , -1082130432
-0.8 , -1085485875
-0.6 , -1088841318
-0.4 , -1093874483
-0.2 , -1102263091
0 , 0
0.2 , 1045220557
0.4 , 1053609165
0.6 , 1058642330
0.8 , 1061997773
1 , 1065353216

Binary representation is simple as just using the %d format
Land code: 290717696, Take off code: 290718208
Run Code Online (Sandbox Code Playgroud)

最后,我的问题是,如何在 R 中重现此功能/转换?

谢谢堆,伊多

编辑 1

我在 R 中找到了一个使用 base 函数进行二进制到 Int 转换的解决方案 strtoi

(land <- strtoi("10001010101000000000000000000", base=2))
[1] 290717696
(takeOff <- land + strtoi("1000000000", base=2))
[1] 290718208
Run Code Online (Sandbox Code Playgroud)

编辑 2

不断扫描网络以寻找解决方案,并找到了一些组合在一起得到我想要的转换,可能不是以最优雅的方式。首先,我写了一个函数来计算尾数和指数:

find_mantissa <- function(f) {
  i <- 1 ; rem <- abs(f) ; mantissa <- NULL
  man_dec_point <- FALSE
  while (length(mantissa)<24) {
    temp_rem <- rem-2^-i
    if (!isTRUE(man_dec_point)) {
      if (temp_rem>=0) {
        man_dec_point <- TRUE 
        mantissa <- "." 
      }
    } else {
      mantissa<-c(mantissa,ifelse(temp_rem>=0, "1", "0"))
    }
    rem <- ifelse(temp_rem>=0, temp_rem, rem)
    i<-i+1 
    next
  }
  return(c(paste0(mantissa[-1], collapse=""),24-i))
}

find_mantissa(0.68)
[1] "01011100001010001111010" "-1"
Run Code Online (Sandbox Code Playgroud)

然后我使用了一个从 r-bloggers 改编的函数(抱歉没有包含链接,我仅限于 2 个链接):

dec2binstr<-function(p_number) {
  bin_str<-NULL
  while (p_number > 0) {
    digit<-p_number %% 2
    p_number<-floor(p_number / 2)
    bin_str<-paste0(digit,bin_str)
  }
  return(bin_str)
}

dec2binstr(127-1)
[1] "1111110"
Run Code Online (Sandbox Code Playgroud)

最后,我将它全部包装在一个函数中,通过将符号位粘贴在一起(始终使用“0”,但将整个字符串反转为负二进制并添加 - 符号到结果整数)、指数位(左填充 0)和尾数。我还添加了另一个函数,而不是strtoi无法处理负签名二进制文件(感谢我在 SO 上找到的解决方案)。

str2num <- function(x) {
  y <- as.numeric(strsplit(x, "")[[1]])
  sum(y * 2^rev((seq_along(y)-1)))
}
float2Int <- function(decfloat){
  bit32 <- ifelse(decfloat<0,-1, 1)
  mantissa <- find_mantissa(decfloat)
  exp <- dec2binstr(127+as.numeric(mantissa[2]))
  long_exp <- paste0(rep("0",8-stri_length(exp)),exp)
  unsigned <- paste0(long_exp,mantissa[1] )
  if (decfloat<0) {
    unsigned <- sapply(lapply(strsplit(unsigned, split=NULL), 
                              function(x) ifelse(x=="0","1", "0")), paste0, collapse="")
  }
  binary <- paste0("0",unsigned)
  return(c(binary, bit32*str2num(binary)))
}

float2Int(0.468)
[1] "00111110111011111001110110110010" "1055890866"                      
> float2Int(-0.468)
[1] "01000001000100000110001001001101" "-1091592781"
Run Code Online (Sandbox Code Playgroud)

获得这个解决方案是一段相当长的旅程,我确信它不是最有效的代码实现(并且不确定它对于大于 1 或小于 -1 的浮点数是否正确),但它适用于我的目的。

任何关于如何改进此代码的评论都将受到高度重视。

干杯,伊多