rdecimalbase-conversion

Converting Numbers from Base 10 to Base 60


Recently, I was reading about the Ancient Babylonian Civilization that used a number system with base 60 instead of base 10. Even with this number system at base 60, they were still able to approximate the square root of 2 — and that too, thousands of years ago!

enter image description here

I was curious about this, and wanted to see how numbers from our decimal system (base 10) can be converted into the sexagesimal system (base 60). Using the R programming language, I found this link in which an answer is provided on converting numbers from some base to a different base.

However, it seems here that the base can only be between 2 and 36 (I want base 60):

base <- function(b, base = 10)
{
  base <- as.integer(base)
  if(base > 36 | base < 2) stop("'base' must be between 2 and 36.")
  
  structure(lapply(b, function(x) 
    {
      n   <- ceiling(log(x, base))
      vec <- numeric()
      val <- x
      
      while(n >= 0)
      {
        rem <- val %/% base^n
        val <- val - rem * base^n
        vec <- c(vec, rem)
        n <- n - 1
      }
      
      while(vec[1] == 0 & length(vec) > 1) vec <- vec[-1]
      structure(x, base = base, representation = vec) 
    }), class = "base")
}

The article that I linked to reads in the headline "One eighth equals seven and thirty in this strange base 60 world" - I would like to see this and convert "1/8" from the decimal system into "7 and 30" in the sexagesimal system.

Can someone please help me with this?


Solution

  • The code as given almost works. The limitation to bases < 36 is only there because the original author wanted to express the values with the symbols [0-9A-Z]. Removing that limitation and extending the algorithm to allow extra digits 'after the decimal point' (or 'after the sexagesimal point' in the case of base 60 :-) ) we get something that almost works (function definition below):

    base(1/8, base = 60, digits = 6)
    [[1]]
    [1] 0.125
    attr(,"base")
    [1] 60
    attr(,"representation")
    [1]  7 29 59 59 59 59
    
    attr(,"class")
    [1] "base"
    

    Instead of "7 30" we get "7 29 (59 repeating)", which is analogous to doing a decimal calculation that should be 0.2 and instead getting 0.1999....

    This would presumably be fixable with an appropriate 'numeric fuzz' threshold.

    The other thing that's missing from the code, now that it does fractional parts, is that the result should return information that tells you where the 'decimal' point is located (at the simplest, including the value of digits in the output).

    There are other aspects of the code that could be improved (e.g. pre-allocating vec rather than building it up iteratively).


    base <- function(b, base = 10, digits = 0) {
      base <- as.integer(base)
      structure(lapply(b, function(x)
        {
          n   <- ceiling(log(x, base))
          vec <- numeric()
          val <- x
    
          while(n >= -1*digits )  {
            rem <- val %/% base^n
            val <- val - rem * base^n
            vec <- c(vec, rem)
            n <- n - 1
          }
    
          while(vec[1] == 0 & length(vec) > 1) vec <- vec[-1]
          structure(x, base = base, representation = vec)
        }), class = "base")
    }