Chuyển đổi cơ sở tùy ý [đóng]


10

Tạo một thói quen lấy một mảng các khối trong một hệ thống cơ sở số và chuyển đổi chúng thành một mảng các khối trong một hệ thống cơ sở số khác. Cả hệ thống từ và đến đều tùy ý và nên được chấp nhận làm tham số. Mảng đầu vào có thể là độ dài tùy ý (Nếu sử dụng ngôn ngữ mà độ dài mảng không được lưu trữ với mảng, chẳng hạn như C, tham số độ dài sẽ được truyền cho hàm).

Đây là cách nó nên hoạt động:

fromArray = [1, 1]
fromBase = 256
toBase = 16
result = convertBase(fromArray, fromBase, toBase);

Cái nào sẽ trả về [0, 1, 0, 1]hoặc có thể [1, 0, 1](hàng đầu 0là tùy chọn vì chúng không thay đổi giá trị của câu trả lời).

Dưới đây là một số vectơ kiểm tra:

  1. Vector kiểm tra danh tính

    fromArray = [1, 2, 3, 4]
    fromBase = 16
    toBase = 16
    result = [1, 2, 3, 4]
    
  2. Vector thử nghiệm tầm thường

    fromArray = [1, 0]
    fromBase = 10
    toBase = 100
    result = [10]
    
  3. Vector thử nghiệm lớn

    fromArray = [41, 15, 156, 123, 254, 156, 141, 2, 24]
    fromBase = 256
    toBase = 16
    result = [2, 9, 0, 15, 9, 12, 7, 11, 15, 14, 9, 12, 8, 13, 0, 2, 1, 8]
    
  4. Vector thử nghiệm thực sự lớn

    fromArray = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    fromBase = 2
    toBase = 10
    result = [1, 2, 3, 7, 9, 4, 0, 0, 3, 9, 2, 8, 5, 3, 8, 0, 2, 7, 4, 8, 9, 9, 1, 2, 4, 2, 2, 3]
    
  5. Vector không đều

    fromArray = [41, 42, 43]
    fromBase = 256
    toBase = 36
    result = [1, 21, 29, 22, 3]
    

Các tiêu chí / quy tắc khác:

  1. Tất cả các biến số nguyên phải vừa trong một số nguyên có chữ ký 32 bit tiêu chuẩn cho tất cả các phạm vi đầu vào lành mạnh.

  2. Bạn có thể chuyển đổi thành một đại diện trung gian, miễn là trung gian đó không có gì khác ngoài một mảng gồm các số nguyên có chữ ký 32 bit.

  3. Sẽ xử lý các căn cứ từ 2 đến 256. Không có nhu cầu hỗ trợ các căn cứ cao hơn thế (nhưng nếu bạn muốn, bằng mọi cách).

  4. Mong đợi để xử lý kích thước đầu vào và đầu ra ít nhất lên đến 1000 yếu tố. Một giải pháp chia tỷ lệ thành 2 ^ 32-1 phần tử sẽ tốt hơn, nhưng 1000 là tốt.

  5. Điều này không nhất thiết là về việc có mã ngắn nhất sẽ đáp ứng các quy tắc này. Đó là về việc có mã sạch nhất và thanh lịch nhất.

Bây giờ, điều này không chính xác tầm thường để làm, vì vậy một câu trả lời gần như có thể được chấp nhận!


Có phải số 1 có nghĩa là chúng ta không thể sử dụng loại bigint?
Keith Randall

@Keith: Đúng. Chỉ có số nguyên 32 bit.
ircmaxell

Bạn nói "số nguyên đã ký" nhưng các ví dụ chỉ dành cho số nguyên dương, vì vậy: chúng ta có phải xử lý phủ định không?
Eelvex

@Eelvex: Tôi không thấy cần phải xử lý tiêu cực. Nếu một tiêu cực được xử lý, nó sẽ nằm ngoài bộ chuyển đổi.
ircmaxell

Có phải chúng luôn luôn là số nguyên?
Peter Olson

Câu trả lời:


8

Con trăn

# divides longnum src (in base src_base) by divisor
# returns a pair of (longnum dividend, remainder)
def divmod_long(src, src_base, divisor):
  dividend=[]
  remainder=0
  for d in src:
    (e, remainder) = divmod(d + remainder * src_base, divisor)
    if dividend or e: dividend += [e]
  return (dividend, remainder)

def convert(src, src_base, dst_base):
  result = []
  while src:
    (src, remainder) = divmod_long(src, src_base, dst_base)
    result = [remainder] + result
  return result

Cảm ơn bạn. Tôi đã tìm kiếm một thói quen như thế này. Tôi phải mất một thời gian để chuyển đổi nó thành Javascript. Có lẽ tôi sẽ chơi golf một chút và đăng lên đây để giải trí.
Stephen Perelson

5

Đây là một giải pháp Haskell

import Data.List
import Control.Monad

type Numeral = (Int, [Int])

swap              ::  (a,b) -> (b,a)
swap (x,y)        =   (y,x)

unfoldl           ::  (b -> Maybe (b,a)) -> b -> [a]
unfoldl f         =   reverse . unfoldr (fmap swap . f)

normalize         ::  Numeral -> Numeral
normalize (r,ds)  =   (r, dropWhile (==0) ds)

divModLongInt            ::  Numeral -> Int -> (Numeral,Int)
divModLongInt (r,dd) dv  =   let  divDigit c d = swap ((c*r+d) `divMod` dv)
                                  (remainder, quotient) = mapAccumR divDigit 0 (reverse dd)
                             in   (normalize (r,reverse quotient), remainder)

changeRadixLongInt       ::  Numeral -> Int -> Numeral
changeRadixLongInt n r'  =   (r', unfoldl produceDigit n)
  where  produceDigit  (_,[])   =  Nothing
         produceDigit  x        =  Just (divModLongInt x r')

changeRadix :: [Int] -> Int -> Int -> [Int]
changeRadix digits origBase newBase = snd $ changeRadixLongInt (origBase,digits) newBase

doLine line = let [(digits,rest0)] = reads line
                  [(origBase,rest1)] = reads rest0
                  [(newBase,rest2)] = reads rest1
              in show $ changeRadix digits origBase newBase

main = interact (unlines . map doLine . lines)

Và chạy các bài kiểm tra từ câu hỏi:

$ ./a.out 
[1,2,3,4] 16 16
[1,2,3,4]
[1,0] 10 100
[10]
[41, 15, 156, 123, 254, 156, 141, 2, 24] 256 16
[2,9,0,15,9,12,7,11,15,14,9,12,8,13,0,2,1,8]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 2 10
[1,2,3,7,9,4,0,0,3,9,2,8,5,3,8,0,2,7,4,8,9,9,1,2,4,2,2,3]
[41, 42, 43] 256 36
[1,21,29,22,3]

Tuyệt vời. Thật tuyệt vời! Bây giờ, nếu chỉ tôi có thể hiểu nó: -) ... (nhưng đó là nhiệm vụ của tôi bây giờ) ...
ircmaxell

5

R

Xử lý nhiều ngàn yếu tố * trong vòng chưa đầy một phút.

addb <- function(v1,v2,b) {
    ml <- max(length(v1),length(v2))
    v1 <- c(rep(0, ml-length(v1)),v1)
    v2 <- c(rep(0, ml-length(v2)),v2)
    v1 = v1 + v2
    resm = v1%%b
    resd = c(floor(v1/b),0)
    while (any(resd != 0)) {
        v1 = c(0,resm) + resd
        resm = v1%%b
        resd = c(floor(v1/b),0)
    }
    while (v1[1] == 0) v1 = v1[-1]
    return(v1)
}

redb <- function(v,b) {
    return (addb(v,0,b))
}

mm = rbind(1)

mulmat <- function(fromb, tob, n) {
    if (dim(mm)[2] >= n) return(mm)
    if (n == 1) return(1)
    newr = addb(mulmat(fromb,tob,n-1) %*% rep(fromb-1,n-1), 1, tob)
    newm = mulmat(fromb,tob,n-1)
    while (is.null(dim(newm)) || dim(newm)[1] < length(newr)) newm = rbind(0,newm)
    mm <<-  cbind(newr, newm)
    return(mm)
}

dothelocomotion <- function(fromBase, toBase, v) {
    mm  <<- rbind(1)
    return(redb(mulmat(fromBase, toBase, length(v)) %*% v, toBase))
}

* cho> 500 phần tử bạn phải tăng mức đệ quy mặc định hoặc không đặt lại mmma trận trêndothelocomotion()

Ví dụ:

v1 = c(41, 15, 156, 123, 254, 156, 141, 2, 24)
dothelocomotion(256,16,v1)
2  9  0 15  9 12  7 11 15 14  9 12  8 13  0  2  1  8

dothelocomotion(256,36,c(41,42,43))
1 21 29 22  3

dothelocomotion(2,10, rep(1,90))
1 2 3 7 9 4 0 0 3 9 2 8 5 3 8 0 2 7 4 8 9 9 1 2 4 2 2 3

3

Một phiên bản JavaScript ít bị xáo trộn và nhanh hơn:

function convert (number, src_base, dst_base)
{
    var res = [];
    var quotient;
    var remainder;

    while (number.length)
    {
        // divide successive powers of dst_base
        quotient = [];
        remainder = 0;
        var len = number.length;
        for (var i = 0 ; i != len ; i++)
        {
            var accumulator = number[i] + remainder * src_base;
            var digit = accumulator / dst_base | 0; // rounding faster than Math.floor
            remainder = accumulator % dst_base;
            if (quotient.length || digit) quotient.push(digit);
        }

        // the remainder of current division is the next rightmost digit
        res.unshift(remainder);

        // rinse and repeat with next power of dst_base
        number = quotient;
    }

    return res;
}

Thời gian tính toán tăng lên là o (số chữ số 2 ).
Không hiệu quả cho số lượng lớn.
Các phiên bản chuyên biệt mã hóa dòng base64 tận dụng các tỷ lệ cơ sở để tăng tốc độ tính toán.


làm con trai làm việc của chúa
bryc

2

Javascript

Cảm ơn Keith Randall cho câu trả lời Python của bạn. Tôi đã vật lộn với những chi tiết vụn vặt trong giải pháp của mình và cuối cùng đã sao chép logic của bạn. Nếu bất cứ ai đang bỏ phiếu cho giải pháp này vì nó hoạt động thì vui lòng cũng bỏ phiếu cho giải pháp của Keith.

function convert(src,fb,tb){
  var res=[]
  while(src.length > 0){
    var a=(function(src){
      var d=[];var rem=0
      for each (var i in src){
        var c=i+rem*fb
        var e=Math.floor(c/tb)
        rem=c%tb
        d.length||e?d.push(e):0
      }
      return[d,rem]
    }).call(this,src)
    src=a[0]
    var rem=a[1]
    res.unshift(rem)
  }
  return res
}

Xét nghiệm

console.log(convert([1, 2, 3, 4], 16, 16))
console.log(convert([1, 0], 10, 100))
console.log(convert([41, 15, 156, 123, 254, 156, 141, 2, 24], 256, 16))
console.log(convert([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 2, 10))
console.log(convert([41, 42, 43], 256, 36))

/*
Produces:
[1, 2, 3, 4]
[10]
[2, 9, 0, 15, 9, 12, 7, 11, 15, 14, 9, 12, 8, 13, 0, 2, 1, 8]
[1, 2, 3, 7, 9, 4, 0, 0, 3, 9, 2, 8, 5, 3, 8, 0, 2, 7, 4, 8, 9, 9, 1, 2, 4, 2, 2, 3]
[1, 21, 29, 22, 3]
*/

Điều này có thể được thu hẹp rất nhiều, nhưng tôi thực sự muốn sử dụng nó cho một dự án phụ nhỏ. Vì vậy, tôi đã giữ cho nó có thể đọc được (phần nào) và cố gắng kiểm tra các biến.


javascript như thế nào? cho mỗi?
Hernán Eche

Không có tên biến trên 3 ký tự, for eachtuyên bố không dùng nữa và các cấu trúc tưới mắt như d.length||e?d.push(e):0... Đây có phải là một thách thức mã bị che giấu hay cái gì đó? Bạn có thể viết điều tương tự với một cú pháp dễ hiểu và hiệu suất tốt hơn.

@kuroineko Đây là mã golf. Bạn đã mong chờ điều gì? Mã sạch, dễ đọc bằng cách sử dụng các tiêu chuẩn cập nhật? Tôi không bao giờ tuyên bố câu trả lời của tôi là hoàn hảo và tôi chắc chắn sẽ không sử dụng nó như trong một dự án sản xuất.
Stephen Perelson

Vâng, tôi thực sự cần thuật toán này trong JavaScript vì một số lý do và tôi đã phải viết lại từ đầu, lấy giải pháp python làm cơ sở. Tôi đánh giá cao sự đóng góp của bạn, nhưng với mục đích thực tế, hầu như không thể sử dụng được IMHO.

2

Toán học

Không có biến nào được xác định, bất kỳ đầu vào nào được chấp nhận miễn là nó phù hợp với bộ nhớ.

f[i_, sb_, db_] := IntegerDigits[FromDigits[i, sb], db];

Lái thử

f[{1,2,3,4},16,16]
f[{1,0},10,100]
f[{41,15,156,123,254,156,141,2,24},256,16]
f[{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},2,10]
f[{41,42,43},256,36]

Ngoài

{1,2,3,4}
{10}
{2,9,0,15,9,12,7,11,15,14,9,12,8,13,0,2,1,8}
{1,2,3 7,9,4,0,0,3,9,2,8,5,3,8,0,2,7,4,8,9,9,1,2,4,2,2,3}
{1,21,29,22,3}

1

Scala:

def toDecimal (li: List[Int], base: Int) : BigInt = li match {                       
  case Nil => BigInt (0)                                                             
  case x :: xs => BigInt (x % base) + (BigInt (base) * toDecimal (xs, base)) }  

def fromDecimal (dec: BigInt, base: Int) : List[Int] =
  if (dec==0L) Nil else (dec % base).toInt :: fromDecimal (dec/base, base)

def x2y (value: List[Int], from: Int, to: Int) =
  fromDecimal (toDecimal (value.reverse, from), to).reverse

Mã kiểm tra với các bài kiểm tra:

def test (li: List[Int], from: Int, to: Int, s: String) = {
 val erg= "" + x2y (li, from, to)
 if (! erg.equals (s))
   println ("2dec: " + toDecimal (li, from) + "\n\terg: " + erg + "\n\texp: " + s)
}   

 test (List (1, 2, 3, 4), 16, 16, "List(1, 2, 3, 4)")
 test (List (1, 0), 10, 100, "List(10)")
 test (List (41, 15, 156, 123, 254, 156, 141, 2, 24), 256, 16, "List(2, 9, 0, 15, 9, 12, 7, 11, 15, 14, 9, 12, 8, 13, 0, 2, 1, 8)") 
 test (List (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), 
   2, 10, "List(1, 2, 3, 7, 9, 4, 0, 0, 3, 9, 2, 8, 5, 3, 8, 0, 2, 7, 4, 8, 9, 9, 1, 2, 4, 2, 2, 3)") 
 test (List (41, 42, 43), 256, 36, "List(1, 21, 29, 22, 3)")

Đã qua tất cả các bài kiểm tra.


1

J, 109 105

Xử lý hàng ngàn chữ số không có mồ hôi. Không có số nguyên nào bị hại!

e=:<.@%,.|~
t=:]`}.@.(0={.)@((e{:)~h=:+//.@)^:_
s=:[t[:+/;.0]*|.@>@(4 :'x((];~[t((*/e/)~>@{.)h)^:(<:#y))1')

Ví dụ

256 16 s 41 15 156 123 254 156 141 2 24
2 9 0 15 9 12 7 11 15 14 9 12 8 13 0 2 1 8

256 36 s 41 42 43
1 21 29 22 3

16 16 s 1 2 3 4
1 2 3 4

256 46 s ?.1000$45
14 0 4 23 42 7 11 30 37 10 28 44 ...

time'256 46 s ?.3000$45'  NB. Timing conversion of 3000-vector.
1.96s

Nó được ngắn hơn.


0

Smalltalk, 128

o:=[:n :b|n>b ifTrue:[(o value:n//b value:b),{n\\b}]ifFalse:[{n}]].
f:=[:a :f :t|o value:(a inject:0into:[:s :d|s*f+d])value:t].

kiểm tra:

f value:#[41 15 156 123 254 156 141 2 24]
  value:256
  value:16. 
    -> #(2 9 0 15 9 12 7 11 15 14 9 12 8 13 0 2 1 8)

f value:#[1 2 3 4]
  value:16
  value:16.
    -> #(1 2 3 4)

f value:#[1 0]
  value:10
  value:100.
    -> #(10)

f value:#[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
  value:2
  value:10.
    -> #(1 2 3 7 9 4 0 0 3 9 2 8 5 3 8 0 2 7 4 8 9 9 1 2 4 2 2 3)

f value:#[41 42 43]
  value:256
  value:36.
    -> #(1 21 29 22 3)

và để giải trí đặc biệt của bạn ( thử thách: tìm hiểu, điều gì đặc biệt về giá trị đầu vào ):

f value:#[3 193 88 29 73 27 40 245 35 194 58 189 243 91 104 156 144 128 0 0 0 0]
  value:256
  value:1000.
    -> #(1 405 6 117 752 879 898 543 142 606 244 511 569 936 384 0 0 0) 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.