Keyfi Temel Dönüşüm [kapalı]


10

Bir sayısal temel sistemdeki bir dizi bloğu alan bir rutin oluşturun ve bunları başka bir sayısal temel sistemdeki bir dizi bloğa dönüştürün. Hem gelen hem de sistemler isteğe bağlıdır ve bir parametre olarak kabul edilmelidir. Giriş dizisi isteğe bağlı bir uzunluk olabilir (dizi uzunluklarının diziyle birlikte saklanmadığı bir dil kullanılıyorsa, örneğin C, işleve bir length parametresi iletilmelidir).

Nasıl olması gerektiği aşağıda açıklanmıştır:

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

Hangisi geri dönmeli [0, 1, 0, 1]ya da büyük olasılıkla [1, 0, 1]( 0yanıtın değerini değiştirmedikleri için önde gelenler isteğe bağlıdır).

İşte bazı test vektörleri:

  1. Kimlik testi vektör

    fromArray = [1, 2, 3, 4]
    fromBase = 16
    toBase = 16
    result = [1, 2, 3, 4]
    
  2. Önemsiz Test Vektör

    fromArray = [1, 0]
    fromBase = 10
    toBase = 100
    result = [10]
    
  3. Büyük Test Vektör

    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. Gerçekten büyük Test vektör

    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. Eşit Olmayan Temel Vektör

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

Diğer kriterler / kurallar:

  1. Tüm tamsayı değişkenleri, tüm aklı başında girdi aralıkları için standart bir 32 bit işaretli tam sayıya sığmalıdır.

  2. Aracı 32 bit işaretli tam sayı dizisinden başka bir şey olmadığı sürece, bir ara temsile dönüştürebilirsiniz.

  3. 2'den 256'ya kadar üsleri ele almayı bekleyin. Bundan daha yüksek üsleri desteklemeye gerek yoktur (ancak isterseniz elbette).

  4. Giriş ve çıkış boyutlarını en az 1000 öğeye kadar işlemeyi bekleyin . 2 ^ 32-1 öğelerine ölçeklenen bir çözüm daha iyi olurdu, ancak 1000 gayet iyi.

  5. Bu mutlaka bu kuralları karşılayacak en kısa koda sahip olmakla ilgili değildir. En temiz ve en zarif koda sahip olmakla ilgilidir.

Şimdi, bu tam olarak önemsiz değil, bu yüzden neredeyse işe yarayan bir cevap kabul edilebilir!


# 1, bigint tipini kullanamayacağımız anlamına mı geliyor?
Keith Randall

@Keith: Doğru. Sadece 32 bit tamsayılar.
ircmaxell

"İşaretli tamsayı" diyorsunuz, ancak örnekler yalnızca pozitif tamsayılar içindir, bu yüzden: negatifleri ele almamız gerekir mi?
Eelvex

@Eelvex: Negatifleri ele almaya gerek görmüyorum. Bir negatif işlenirse, dönüştürücünün dışında olur.
ircmaxell

Daima tamsayı bazlar mı?
Peter Olson

Yanıtlar:


8

piton

# 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

Teşekkür ederim. Böyle bir rutin arıyordum. Yine de Javascript dönüştürmek biraz zaman aldı. Muhtemelen biraz golf yapacağım ve eğlenmek için buraya göndereceğim.
Stephen Perelson

5

İşte bir Haskell çözümü

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)

Ve sorudan testlerin yapılması:

$ ./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]

Vay canına. Bu harika! Şimdi, eğer anlayabilseydim: -) ... (ama şimdi benim görevim) ...
ircmaxell

5

R,

Binlerce öğeyi * bir dakikadan daha kısa sürede işler.

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))
}

Varsayılan tekrarlama düzeyini yükseltmek zorunda * 500 elemanlarının> için veya sıfırlamak yok mmüzerinde matrisidothelocomotion()

Örnekler:

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

Daha az gizlenmiş ve daha hızlı bir JavaScript sürümü:

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;
}

Hesaplama süresi o olarak büyür (basamak sayısı 2 ).
Büyük sayılar için çok verimli değil.
Özel sürümler satır base64 kodlaması, hesaplamaları hızlandırmak için taban oranlarından yararlanır.


tanrının iş oğlu yapıyor
bryc

2

JavaScript

Keith Randall, Python'un cevabınız için teşekkür ederim. Çözümümün minutiaları ile mücadele ediyordum ve sonunda mantığınızı kopyaladım. Herkes bu çözüm için işe yaradığı için oy veriyorsa, lütfen Keith'in çözümüne de oy verin.

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
}

Testler

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]
*/

Bu muhtemelen çok daraltılmış olabilir, ama aslında küçük bir yan proje için kullanmak istiyorum. Bu yüzden okunabilir (biraz) ve değişkenleri kontrol altında tutmaya çalıştım.


javascript nasıl? her biri için?
Hernán Eche

3 karakterin üzerinde değişken isimleri, kullanımdan kaldırılmış for eachifadeler ve göz sulandırıcı yapılar gibi d.length||e?d.push(e):0... Bu gizlenmiş bir kod meydan okuması falan mı? Aynı şeyi anlaşılabilir bir sözdizimi ve daha iyi performanslarla yazabilirsiniz.

@kuroineko Bu kod golfü. Ne bekliyordun? Güncel standartlar kullanılarak temiz, okunabilir kod? Cevabımın mükemmel olduğunu hiç iddia etmedim ve kesinlikle bir üretim projesinde olduğu gibi kullanmayacağım.
Stephen Perelson

Aslında bu algoritmayı bir nedenden dolayı JavaScript'e ihtiyacım vardı ve python çözümünü bir temel olarak alarak sıfırdan yeniden yazmak zorunda kaldım. Katkınızı takdir ediyorum, ancak pratik amaçlar için IMHO'da neredeyse hiç kullanışlı değildi.

2

Mathematica

Hiçbir değişken tanımlanmadı, herhangi bir girdi belleğe sığdığı sürece kabul edildi.

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

Test sürüşü:

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]

Dışarı

{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

Testli test kodu:

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)")

Tüm testleri geçti.


1

J, 109 105

Binlerce basamağı terlemez. Tamsayı zarar görmedi!

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

Örnekler

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

Kısalıyor.


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].

testler:

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)

ve özel eğlenceniz için ( zorluk: anlayın, giriş değeri hakkında çok özel olan şey ):

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) 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.