การแปลงฐานโดยพลการ [ปิด]


10

สร้างชุดคำสั่งที่ใช้อาร์เรย์ของบล็อกในระบบฐานตัวเลขหนึ่งและแปลงให้เป็นอาร์เรย์ของบล็อกในระบบฐานตัวเลขอื่น ทั้งจากและสู่ระบบโดยพลการและควรได้รับการยอมรับเป็นพารามิเตอร์ อาเรย์อินพุตอาจเป็นความยาวตามอำเภอใจ (หากใช้ภาษาที่ไม่ได้เก็บความยาวของอาเรย์ไว้กับอาเรย์เช่น C พารามิเตอร์ความยาวควรถูกส่งผ่านไปยังฟังก์ชัน)

นี่คือวิธีการใช้งาน:

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

สิ่งใดที่ควรส่งคืน[0, 1, 0, 1]หรืออาจเป็นไปได้[1, 0, 1](การนำหน้า0s เป็นทางเลือกเนื่องจากไม่เปลี่ยนค่าของคำตอบ)

นี่คือเวกเตอร์ทดสอบบางส่วน:

  1. การทดสอบเอกลักษณ์เวกเตอร์

    fromArray = [1, 2, 3, 4]
    fromBase = 16
    toBase = 16
    result = [1, 2, 3, 4]
    
  2. Vector ทดสอบเล็กน้อย

    fromArray = [1, 0]
    fromBase = 10
    toBase = 100
    result = [10]
    
  3. เวกเตอร์ทดสอบขนาดใหญ่

    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. เวกเตอร์ทดสอบที่ใหญ่จริงๆ

    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. เวกเตอร์ฐานที่ไม่สม่ำเสมอ

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

เกณฑ์ / กฎอื่น ๆ :

  1. ตัวแปรเลขจำนวนเต็มทั้งหมดควรพอดีภายในจำนวนเต็มที่มีลายเซ็นมาตรฐาน 32 บิตสำหรับช่วงอินพุตที่มีสติทั้งหมด

  2. คุณสามารถแปลงเป็นตัวแทนคนกลางได้ตราบใดที่คนกลางไม่มีอะไรมากไปกว่าจำนวนเต็มจำนวน 32 บิต

  3. คาดหวังว่าจะรองรับฐานได้ตั้งแต่ 2 ถึง 256 ไม่จำเป็นต้องรองรับฐานที่สูงกว่านั้น (แต่ถ้าคุณต้องการโดยทั้งหมด)

  4. คาดว่าจะรองรับขนาดอินพุตและเอาต์พุตอย่างน้อย 1,000 อิลิเมนต์ วิธีแก้ปัญหาที่ปรับขนาดเป็น 2 ^ 32-1 องค์ประกอบน่าจะดีกว่า แต่ 1,000 ก็ใช้ได้

  5. นี่ไม่จำเป็นต้องเกี่ยวกับการมีรหัสสั้นที่สุดที่จะเป็นไปตามกฎเหล่านี้ มันเกี่ยวกับการมีโค้ดที่สะอาดและหรูหราที่สุด

ทีนี้มันก็ไม่ได้น่าสนใจอะไรนักดังนั้นคำตอบที่เกือบจะเป็นที่ยอมรับ!


# 1 หมายความว่าเราไม่สามารถใช้ประเภทใหญ่หรือไม่
Keith Randall

@ Keith: ถูกต้อง จำนวนเต็ม 32 บิตเท่านั้น
ircmaxell

คุณพูดว่า "จำนวนเต็มแบบมีเครื่องหมาย" แต่ตัวอย่างมีไว้สำหรับจำนวนเต็มบวกเท่านั้นดังนั้นเราต้องจัดการกับค่าลบหรือไม่
Eelvex

@Eevenx: ฉันไม่เห็นความต้องการจัดการเชิงลบ หากมีการจัดการเชิงลบมันจะอยู่นอกแปลง
ircmaxell

พวกเขามักจะเป็นจำนวนเต็มฐาน?
Peter Olson

คำตอบ:


8

หลาม

# 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

ขอบคุณ. ฉันกำลังมองหางานประจำเช่นนี้ ฉันใช้เวลาสักครู่หนึ่งในการแปลงเป็น Javascript ฉันอาจจะเล่นกอล์ฟนิดหน่อยแล้วโพสต์ที่นี่เพื่อความสนุก
Stephen Perelson

5

นี่คือทางออกของ 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)

และทำการทดสอบจากคำถาม:

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

โอ้ว้าว. ที่น่ากลัว! ตอนนี้ถ้าเพียง แต่ฉันสามารถเข้าใจได้: -) ... (แต่ตอนนี้งานของฉันคือตอนนี้) ...
ircmaxell

5

R

จับหลายพันคนขององค์ประกอบ*ในเวลาน้อยกว่าหนึ่งนาที

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

* สำหรับ> 500 องค์ประกอบคุณต้องเพิ่มระดับการเรียกซ้ำเริ่มต้นหรือไม่ต้องรีเซ็ตmmเมทริกซ์dothelocomotion()

ตัวอย่าง:

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

เวอร์ชัน JavaScript ที่ซับซ้อนน้อยกว่าและเร็วกว่า:

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

เวลาการคำนวณเพิ่มขึ้นเป็น o (จำนวนหลัก2 )
ไม่ค่อยมีประสิทธิภาพสำหรับคนจำนวนมาก
การเข้ารหัส line64 เวอร์ชั่นพิเศษใช้ประโยชน์จากอัตราส่วนฐานเพื่อเพิ่มความเร็วในการคำนวณ


ทำลูกชายที่ทำงานของพระเจ้า
bryc

2

จาวาสคริ

ขอบคุณ Keith Randall สำหรับคำตอบของ Python ฉันกำลังดิ้นรนกับข้อบกพร่องเล็ก ๆ น้อย ๆ ของการแก้ปัญหาของฉันและจบลงด้วยการคัดลอกตรรกะของคุณ หากมีใครให้คะแนนโหวตโซลูชันนี้เพราะใช้งานได้โปรดให้คะแนนโหวตโซลูชันของ 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
}

การทดสอบ

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

นี่อาจจะหดมาก แต่จริง ๆ แล้วฉันต้องการใช้สำหรับโครงการเล็ก ๆ น้อย ๆ ดังนั้นฉันจึงสามารถอ่านได้ (ค่อนข้าง) และพยายามเก็บตัวแปรไว้ในการตรวจสอบ


มันเป็นจาวาสคริปต์อย่างไร? แต่ละ?
Hernán Eche

ไม่มีชื่อตัวแปรด้านบน 3 ตัวอักษรfor eachคำสั่งที่เลิกใช้และโครงสร้างที่น่าสนใจอย่างเช่นd.length||e?d.push(e):0... นี่เป็นความท้าทายของโค้ดที่ยุ่งเหยิงหรือบางอย่าง? คุณสามารถเขียนสิ่งเดียวกันด้วยไวยากรณ์ที่เข้าใจและประสิทธิภาพที่ดีขึ้น

@kuroineko นี่คือรหัสกอล์ฟ คุณคาดหวังอะไร ทำความสะอาดโค้ดที่อ่านได้โดยใช้มาตรฐานล่าสุดหรือไม่ ฉันไม่เคยอ้างว่าคำตอบของฉันสมบูรณ์แบบและแน่นอนว่าฉันจะไม่ใช้มันอย่างที่เป็นในโครงการผลิต
Stephen Perelson

เอาล่ะฉันต้องการอัลกอริทึมนี้ใน JavaScript ด้วยเหตุผลบางอย่างและฉันต้องเขียนใหม่ตั้งแต่ต้นโดยใช้โซลูชันไพ ธ อนเป็นฐาน ฉันซาบซึ้งในความช่วยเหลือของคุณ แต่สำหรับวัตถุประสงค์ในทางปฏิบัติมันแทบจะไม่มีประโยชน์เลยสำหรับ IMHO

2

มาติกา

ไม่ได้กำหนดตัวแปรไว้อินพุตใด ๆ ที่ยอมรับได้ตราบเท่าที่เหมาะสมกับหน่วยความจำ

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

ทดลองขับ:

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]

ออก

{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

Testcode ด้วยการทดสอบ:

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

ผ่านการทดสอบทั้งหมด


1

J, 109 105

จัดการกับหลักพันไม่มีเหงื่อ ไม่มีจำนวนเต็มทำร้าย!

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

ตัวอย่าง

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

มันสั้นลง


0

สมอลล์ทอล์ค, 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].

การทดสอบ:

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)

และเพื่อความบันเทิงพิเศษของคุณ ( ความท้าทาย: หาว่ามีอะไรพิเศษเกี่ยวกับค่าอินพุต ):

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) 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.