Convert hex to decimal in R - r

I found out that there is function called .hex.to.dec in the fBasics package.
When I do .hex.to.dec(a), it works.
I have a data frame with a column samp_column consisting of such values:
a373, 115c6, a373, 115c6, 176b3
When I do .hex.to.dec(samp_column), I get this error:
"Error in nchar(b) : 'nchar()' requires a character vector"
When I do .hex.to.dec(as.character(samp_column)), I get this error:
"Error in rep(base.out, 1 + ceiling(log(max(number), base =
base.out))) : invalid 'times' argument"
What would be the best way of doing this?

Use base::strtoi to convert hexadecimal character vectors to integer:
strtoi(c("0xff", "077", "123"))
#[1] 255 63 123

There is a simple and generic way to convert hex <-> other formats using "C/C++ way":
V <- c(0xa373, 0x115c6, 0xa373, 0x115c6, 0x176b3)
sprintf("%d", V)
#[1] "41843" "71110" "41843" "71110" "95923"
sprintf("%.2f", V)
#[1] "41843.00" "71110.00" "41843.00" "71110.00" "95923.00"
sprintf("%x", V)
#[1] "a373" "115c6" "a373" "115c6" "176b3"

As mentioned in #user4221472's answer, strtoi() overflows with integers larger than 2^31.
The simplest way around that is to use as.numeric().
V <- c(0xa373, 0x115c6, 0x176b3, 0x25cf40000)
as.numeric(V)
#[1] 41843 71110 95923 10149429248
As #MS Berends noted in the comments, "[a]lso notice that just printing V in the console will already print in decimal."

strtoi() has a limitation of 31 bits. Hex numbers with the high order bit set return NA:
> strtoi('0x7f8cff8b')
[1] 2139946891
> strtoi('0x8f8cff8b')
[1] NA

To get a signed value with 16 bits:
temp <- strtoi(value, base=16L)
if (temp>32767){ temp <- -(65535 - temp) }
In a general form:
max_unsigned <- 65535 #0xFFFF
max_signed <- 32767 #0x7FFF
temp <- strtoi(value, base=16L)
if (temp>max_signed){ temp <- -(max_unsigned- temp) }

Related

How to convert character argument (decimal number) to numeric in R?

I want to convert for example the number 167009345.8 to 167009345.8.
I have used lots of ways but I have problems.
For example,
x <- "167009345.8"
class(x) <- "numeric"`
the output is 167009346.
But I want the decimal number 167009345.8.
I have used also as.numeric, but I have the same problem.
Could you please help me?
options(digits=10)
x<-"167009345.8"
as.numeric(x)
[1] 167009345.8
I had to split a long character string into separate decimal numbers. It was very frustrating. Maybe this can spare some others some time:
string = as.character("1.23456, -2.34567, -8.90, +0, +99999.9999, -0.0")
charlist = strsplit(string, "," )
numberlist = lapply(charlist, function(x) (as.numeric(x)))
vector = as.numeric(unlist(numberlist))
vector
[1] 1.23456 -2.34567 -8.90000 0.00000 99999.99990 0.00000

Vectorizing a function that uses strsplit

I am trying to make a function that converts time (in character form) to decimal format such that 1 corresponds to 1 am and 23 corresponds to 11 pm and 24 means the end of the day.
Here are the two function that does this. Here one function vectorizes while other do
time2dec <- function(time0)
{
time.dec <-as.numeric(substr(time0,1,2))+as.numeric(substr(time0,4,5))/60+(as.numeric(substr(time0,7,8)))/3600
return(time.dec)
}
time2dec1 <- function(time0)
{
time.dec <-as.numeric(strsplit(time0,':')[[1]][1])+as.numeric(strsplit(time0,':')[[1]][2])/60+as.numeric(strsplit(time0,':')[[1]][3])/3600
return(time.dec)
}
This is what I get...
times <- c('12:23:12','10:23:45','9:08:10')
#>time2dec(times)
[1] 12.38667 10.39583 NA
Warning messages:
1: In time2dec(times) : NAs introduced by coercion
2: In time2dec(times) : NAs introduced by coercion
#>time2dec1(times)
[1] 12.38667
I know time2dec which is vectorized, gives NA for the last element because it extracts 9: instead of 9 as hour. That is why I created time2dec1 but I do not know why it is not getting vectorized.
I will also be interested in getting a better function for doing what I am trying to do.
I saw this which explain a part of my question but does not provide a clue to do what I am trying.
Don't try to reinvent the wheel:
times1 <- difftime(as.POSIXct(times, "%H:%M:%S", tz="GMT"),
as.POSIXct("0:0:0", "%H:%M:%S", tz="GMT"),
units="hours")
#Time differences in hours
#[1] 12.386667 10.395833 9.136111
as.numeric(times1)
#[1] 12.386667 10.395833 9.136111
In the following we shall use this test vector:
ch <- c('12:23:12','10:23:45','9:08:10')
1) To fix up the solution in the question we prepend a 0 and then replace any string of 3 digits with the last two:
num.substr <- function(...) as.numeric(substr(...))
time2dec <- function(time0) {
t0 <- sub("\\d(\\d\\d)", "\\1", paste0(0, time0))
num.substr(t0, 1, 2) + num.substr(t0, 4, 5) / 60 + num.substr(t0, 7, 8) / 3600
}
time2dec(ch)
## [1] 12.386667 10.395833 9.136111
2) Parsing the string is slightly easier with strapply in the gsubfn package:
strapply(ch, "^(.?.):(..):(..)",
~ as.numeric(h) + as.numeric(m)/60 + as.numeric(s)/36000,
simplify = c)
## [1] 12.383667 10.384583 9.133611
3) We can reduce the string manipulation to just removing the colons and then convert the resulting character string to numeric so we can manipulate it numerically:
num <- as.numeric(gsub(":", "", ch))
num %/% 10000 + num %% 10000 %/% 100 / 60 + num %% 100 / 3600
## [1] 12.386667 10.395833 9.136111
4) The chron package has a "times" class that internally represents times as fractions of a day. Converting that to hours gives an easy solution:
library(chron)
24 * as.numeric(times(ch))
## [1] 12.386667 10.395833 9.136111
ADDED Added more solutions.
as.numeric( strptime(times, "%H:%M:%S")-strptime(Sys.Date(), "%Y-%m-%d" ))
[1] 12.386667 10.395833 9.136111
Basically the same as Roland's but bypassing some steps, and I try to avoid using difftime if I can. Had too many bugs arise because I don't really understand the function or the class ... or something. And when I timed it versus Roland's his was faster. Oh, well.
Emulating #G.Grothendieck's efforts (and essentially working similarly to his elegant strapply solution:
num <- apply( matrix(scan(text=gsub(":", " ", ch), what=numeric(0)),nrow=3), 2,
function(x) x[1]+x[2]/60 +x[3]/3600 )
#Read 9 items
num
#[1] 12.386667 10.395833 9.136111
And this actually answers the original question:
num <- sapply( strsplit(ch, ":"), function(x){ x2 <- as.numeric(x);
x2[1]+x2[2]/60 +x2[3]/3600})
num
#[1] 12.386667 10.395833 9.136111
The following does what you want
sapply(strsplit(times, ":"), function(d) {
sum(as.numeric(d)*c(1,1/60,1/3600))
})
Step by step:
strsplit(times, ":")
returns a list with character vectors. Each character vector contains the three part of the time (hour, minutes, seconds). We now want to convert each of the elements in the list to a numeric values. For this we need to apply a function to each element and put the results of the back into a vector which is what sapply does.
sapply(strsplit(times, ":", function(d) {
})
As for the function. We first need to convert the character values to numeris values using as.numeric. The we multiply the first element with 1, the second with 1/60 and the third with 1/3600 and add the results (for which we use sum). Resulting in
sapply(strsplit(times, ":"), function(d) {
sum(as.numeric(d)*c(1,1/60,1/3600))
})

Convert HH:MM:SS to hours (for more than 24 hours) in R

I would like to convert hours more than 24 hours in R.
For example, I have a dataframe which contains hours and minutes like [HH:MM]:
[1] "111:15" "221:15" "111:15" "221:15" "42:05"
I want them to be converted in hours like this:
"111.25" "221.25" "111.25" "221.25" "42.08333333"
as.POSIXct()
function works for general purpose, but not for more than 24 hours.
You can split the strings with strsplit and use sapply to transform all values.
vec <- c("111:15", "221:15", "111:15", "221:15", "42:05")
sapply(strsplit(vec, ":"), function(x) {
x <- as.numeric(x)
x[1] + x[2] / 60
})
The result:
[1] 111.25000 221.25000 111.25000 221.25000 42.08333
I would just parse the strings with regex. Grab the bit before the : then add on the bit after the : divided by 60
> foo = c("111:15", "221:15", "111:15", "221:15", "42:05")
> foo
[1] "111:15" "221:15" "111:15" "221:15" "42:05"
> as.numeric(gsub("([^:]+).*", "\\1", foo)) + as.numeric(gsub(".*:([0-9]{2})$", "\\1", foo))/60
[1] 111.25000 221.25000 111.25000 221.25000 42.08333
Another possibility is a vectorized function such as:
FUN <- function(time){
hours <- sapply(time,FUN=function(x) as.numeric(strsplit(x,split=":")[[1]][1]))
minutes <- sapply(time,FUN=function(x) as.numeric(strsplit(x,split=":")[[1]][2]))
result <- hours+(minutes/60)
return(as.numeric(result))
}
Where you use strsplit to extract the hours and minutes, of which you then take the sum after dividing the minutes by 60.
You can then use the function like this:
FUN(c("111:15","221:15","111:15","221:15","42:05"))
[1] 111.25000 221.25000 111.25000 221.25000 42.08333
strapplyc Here ia a solution using strapplyc in the gsubfn package. It passes the match to each of the parenthesized regular expressions (i.e. the hours and the minutes) to the function described in the third argument. The function can be specified using the usual R function notation and it also supports a short form using a formula (used here) where the right hand side of the formula is the function body and the left hand side represent the arguments and defaults to the free variables (m, h) in the right hand side. We suppose that the original character vector is ch.
library(gsubfn)
strapply(ch, "(\\d+):(\\d+)", ~ as.numeric(h) + as.numeric(m)/60, simplify = TRUE)
numeric processing Another way is to replace the : with a . and manipulate it numerically into what we want:
num <- as.numeric(chartr(":", ".", ch))
trunc(num) + 100 * (num %% 1) / 60
sub This is yet another approach:
h <- as.numeric(sub(":.*", "", ch))
m <- as.numeric(sub(".*:", "", ch))
h + m / 60
The codes above each gives a numberic result but we could wrap each in as.character(...) if a character result were desired.
read.table
as.matrix(read.table(text = ch, sep = ":")) %*% c(1, 1/60)
eval/parse. This one maipulates each one into an R expression which is evaluated. This one is short but the use of eval is often frowned upon:
sapply(parse(text = sub(":", "+(1/60)*", ch)), eval)
ADDED additional solutions.

Getting numerator and denominator of a fraction in R

Using the function fractions in the library MASS, I can convert a decimal to a fraction:
> fractions(.375)
[1] 3/8
But then how to I extract the numerator and denominator? The help for fractions mentions an attribute "fracs", but I can't seem to access it.
A character representation of the fraction is stored in an attribute:
x <- fractions(0.175)
> strsplit(attr(x,"fracs"),"/")
[[1]]
[1] "7" "40"
You can get the fracs attribute from your fraction object the following way, but it is just the character representation of your fraction :
x <- fractions(.375)
attr(x, "fracs")
# [1] "3/8"
If you want to access numerator and denominator values, you can just split the string with the following function :
getfracs <- function(frac) {
tmp <- strsplit(attr(frac,"fracs"), "/")[[1]]
list(numerator=as.numeric(tmp[1]),denominator=as.numeric(tmp[2]))
}
Which you can use this way :
fracs <- getfracs(x)
fracs$numerator
# [1] 3
fracs$denominator
# [1] 8

format numeric without leading zero

What's the best way to format a numeric so that it does NOT show leading zero. For example:
test = .006
sprintf/format/formatC( ??? ) # should result in ".006"
I believe I answered this once before but can't find it. You cannot tell sprintf() et al about a format that drops the leading zero ... so you have to do it yourself, eg via substring():
R> val <- 0.006
R> aa <- substring(sprintf("%4.3f", val), 2)
R> aa
[1] ".006"
R>
f <- function(x) gsub("^(\\s*[+|-]?)0\\.", "\\1.", as.character(x))
f(0.006)
# ".006"
f(-0.006)
# "-.006"
f("+0.006")
# "+.006"
f(" 0.006")
# " .006"
f(10.05)
# "10.05"
You can always fix it up yourself with regular expression search-and-replace:
library(stringr)
test = .006
str_replace(as.character(test), "^0\\.", ".")
Not the most elegant answer, but it works. Substitute whatever string conversion you like for as.character, such as sprintf with your preferred floating point format.

Resources