Find the BCD difference of a number

20

0

BCD difference

Given an integer n, convert it to BCD (binary-coded decimal) by replacing each decimal digit with its 4-digit binary representation

 234 -> 0 0 1 0 0 0 1 1 0 1 0 0

Then rotate the list of binary digits in order to find the largest and smallest numbers, representable by this list without other rearrangements.

max: 1 1 0 1 0 0 0 0 1 0 0 0  (the entire list rotated left 6 times)
min: 0 0 0 0 1 0 0 0 1 1 0 1 (the entire list rotated right 2 times)

Convert these numbers back to decimal, treating the list of bits as regular binary and subtract the smallest from the largest:

1 1 0 1 0 0 0 0 1 0 0 0 -> 3336
0 0 0 0 1 0 0 0 1 1 0 1 -> 141

3336 - 141 -> 3195

The output is the difference of the largest and smallest numbers found.

Test cases:

234 -> 3195
1234 -> 52155
12 -> 135
975831 -> 14996295
4390742 -> 235954919
9752348061 -> 1002931578825

Galen Ivanov

Posted 2017-11-15T15:31:51.847

Reputation: 13 815

Answers

7

Wolfram Language (Mathematica), 89 88 bytes

Thanks to Jenny_mathy for saving 1 byte.

i=IntegerDigits;Max@#-Min@#&[#~FromDigits~2&/@NestList[RotateRight,Join@@i[i@#,2,4],#]]&

Try it online!

This is terribly inefficient, because it generates n rotations of the BCD of n, which is way more than we need. We can make this is a bit more efficient by saving the result of the Join@@ in k and replacing the # at the end with Length@k. That lets us generate a scatterplot quite easily:

enter image description here

I'm really intrigued by the contrast of local structure and overall chaos.

Martin Ender

Posted 2017-11-15T15:31:51.847

Reputation: 184 808

Max@#-Min@#& saves a byte. right? – J42161217 – 2017-11-16T12:32:45.410

@Jenny_mathy Yeah, thanks! :) – Martin Ender – 2017-11-16T12:33:28.673

1I made this from our solutions Max@#-Min@#&[#~FromDigits~2&/@Partition[s=Join@@(i=IntegerDigits)[i@#,2,4],Tr[1^s],1,1]]& 89 bytes AND efficient. damn that byte! – J42161217 – 2017-11-16T13:00:46.110

Actually the plot is a repeated patern.Those "chaotic clouds" happen every 10^n (the plot "jumps" and create a new one): 1-9,10-99,100-999... here are some different zooms: https://imgur.com/RXLMkco

– J42161217 – 2017-11-16T17:27:12.093

@Jenny_mathy sure, but the structure within these intervals appears very chaotic (with structures only at much smaller scales). – Martin Ender – 2017-11-16T17:33:13.197

It's like throwing a rubber crazy ball in a room and taking snapshots: (1 per sec)(10/0.1sec)(100/0.01sec).All those groups depict 1 sec. The last group has just more data.But it is the same chaotic phenomenon in all scales... I think ;-) – J42161217 – 2017-11-16T17:48:09.937

6

Jelly, 13 bytes

Dd4d2FṙJ$ḄṢIS

Try it online!

How it works

Dd4d2FṙJ$ḄṢIS  Main link. Argument: n

D              Decimal; convert n to base 10 (digit array).
 d4            Divmod 4; map each digit d to [d/4, d%4].
   d2          Divmod 2; map each [d/4, d%4] to [[d/8, d/4%2], [d%4/2, d%2]].
     F         Flatten the resulting 3D binary array.
      ṙJ$      Take all possible rotations.
         Ḅ     Convert each rotation from binary to integer.
          Ṣ    Sort the resulting integer array.
           I   Take the forward differences.
            S  Take the sum.

Dennis

Posted 2017-11-15T15:31:51.847

Reputation: 196 637

4

Python 3, 115 108 bytes

thanks to Jonathan Frech for -7 bytes

k=''.join(f'{int(i):04b}'for i in input())
v=[int(k[i:]+k[:i],2)for i in range(len(k))]
print(max(v)-min(v))

Try it online!

ovs

Posted 2017-11-15T15:31:51.847

Reputation: 21 408

4

PowerShell, 153 bytes

$b=[char[]]-join([char[]]"$args"|%{[convert]::toString(+"$_",2).PadLeft(4,'0')})
($c=$b|%{$x,$y=$b;[convert]::ToInt64(-join($b=$y+$x),2)}|sort)[-1]-$c[0]

Try it online!

Stupid lengthy .NET calls to convert to/from binary really bloats the length here. ;-)

We take input as $args, wrap it in a string, then cast it as a char-array. We loop over each digit, converting the digit toString in base 2 (i.e., turning the digit into a binary number), then .padLeft to make it a four-digit binary number. That resulting array of strings is then -joined into a single string and re-cast as a char-array before being saved into $b.

Next, we loop over $b, which just makes sure we loop enough times to account for every rotation. Each iteration, we peel off the first character into $x and the remaining characters into $y using multiple assignment. Then, we merge them back together into $b=$y+$x to move the first element to the end, i.e., effectively rotating the array by one. That's -joined into a string, which is used as the input to the convert call to turn the string from binary base 2 into an Int64. We then sort all of those resultant numbers and store them into $c. Finally, we take the biggest [-1] and subtract the smallest [0]. That's left on the pipeline and output is implicit.

AdmBorkBork

Posted 2017-11-15T15:31:51.847

Reputation: 41 581

4

Ohm v2, 15 bytes

€b4Ü. 0\;Jγó↕]a

Try it online!

Explanation:

€b4Ü. 0\;Jγó↕]a  Main wire, arguments: a (integer)

€       ;        Map the following over each digit of a...
 b                 Convert to binary
  4Ü               Right-justify w/ spaces to length 4
    . 0\           Replace all spaces with zeroes
         J       Join together binary digits
          γó     Get all possible rotations and convert back to decimal
            ↕    Find the minimum *and* maximum rotation
             ]a  Flatten onto stack and get the absolute difference

Nick Clifford

Posted 2017-11-15T15:31:51.847

Reputation: 1 184

4

JavaScript (ES6), 118 100 99 bytes

f=
n=>(g=m=>Math[m](...[...s=(`0x1`+n-0).toString(2)].map(_=>`0b${s=0+s.slice(2)+s[1]}`)))`max`-g`min`
<input type=number min=0 oninput=o.textContent=f(this.value)><pre id=o>

Edit: Saved 11 bytes thanks to @RickHitchcock. Saved 1 byte thanks to @ETHproductions. Explanation: The 0x1 prefix causes the input to get reparsed as a hexadecimal number, whose binary is the same as the BCD of the original number with a 1 prefix (I think this is golfier than any other way of padding to a multiple of 4 digits). Excluding the prefix, which is changed from 1 to 0, the resulting string is then rotated at each possible position and converted from binary back to decimal. Finally the maximum and minimum are subtracted.

Neil

Posted 2017-11-15T15:31:51.847

Reputation: 95 035

1@RickHitchcock Wrap the string in double backticks... unless you want to write something like .join`` in which case you need triple backticks etc. – Neil – 2017-11-15T22:40:24.120

Good idea to use hexadecimal. Save 11 bytes like this: n=>(g=m=>Math[m](...[...s=(+`0x1${n}`).toString(2).slice(1)]‌​.map(_=>`0b${s=s.sli‌​ce(1)+s[0]}`)))`max`‌​-g`min` – Rick Hitchcock – 2017-11-15T22:44:00.500

1@RickHitchcock Thanks, that helped me... slice... off another 7 bytes by removing another slice too! – Neil – 2017-11-15T22:48:23.657

1The m=>Math[m] trick is great. Perhaps change (+`0x1${n}`) to ('0x1'+n-0) or similar? – ETHproductions – 2017-11-16T03:47:03.747

3

Python 2, 115 113 bytes

  • Saved some bytes thanks to ovs.
  • Saved two bytes thanks to Mr. Xcoder.
b="".join(format(int(n),"04b")for n in`input()`)
b=[int(b[s:]+b[:s],2)for s in range(len(b))]
print max(b)-min(b)

Try it online!

Jonathan Frech

Posted 2017-11-15T15:31:51.847

Reputation: 6 681

3

Pyth, 29 bytes

Ksm.[\04.Bsd`Q-eJSmi.<Kd2lKhJ

Try it here! or Check out the test suite.

Mr. Xcoder

Posted 2017-11-15T15:31:51.847

Reputation: 39 774

-3 or -5 bytes – Steven H. – 2017-11-16T23:45:16.903

3

Husk, 18 bytes

§-▼▲mḋUMṙNṁȯtḋ+16d

Try it online!

There should be a shorter way to convert a digit into its 4-bit binary representation...

Explanation

§-▼▲mḋUMṙNṁȯtḋ+16d
                 d    Get the list of digits of the input
          ṁȯ          For each digit...
              +16      add 16
             ḋ         convert to binary
            t          drop the first digit
       MṙN            Rotate the list by all possible (infinite) numbers
      U               Get all rotations before the first duplicated one
    mḋ                Convert each rotation from binary to int
§-▼▲                  Subtract the minimum from the maximum value

Leo

Posted 2017-11-15T15:31:51.847

Reputation: 8 482

3

APL (Dyalog), 37 34 bytes

{(⌈/-⌊/)2⊥¨(⍳⍵)∘.⌽⊂,↑(4⍴2)∘⊤¨⍎¨⍕⍵}

Try it online!

Uriel

Posted 2017-11-15T15:31:51.847

Reputation: 11 708

3

APL (Dyalog), 31 bytes

Full program body. Prompts for number from STDIN. Prints result to STDOUT.

(⌈/-⌊/)2⊥¨(⍳≢b)⌽¨⊂b←,⍉(4/2)⊤⍎¨⍞

Try it online!

 prompt for line of text from STDIN

⍎¨ execute (evaluate) each (character)

()⊤ encode (anti-base) in the following number system:

4/2 four binary bits

 transpose

, ravel (flatten)

b← store in b (for binary)

 enclose (so that we will use this entire list for each rotation)

()⌽¨ rotate (left) by each of the following amounts:

≢b length of b

indices of that

2⊥¨ decode each from base-2.

() apply the following tacit function to that

⌈/ the max(-reduction)

- minus

⌊/ the min(-reduction)

Adám

Posted 2017-11-15T15:31:51.847

Reputation: 37 779

you could easily trainify this bit: (⍳≢b)⌽¨⊂b← – ngn – 2017-11-18T18:59:40.670

or even better - use (≢,/,⍨) instead of the obvious (⍳∘≢⌽¨⊂) – ngn – 2017-11-18T19:10:22.583

2

Jelly, 21 bytes

DB0;$4¡€ṫ€-3FṙJ$ḄµṀ_Ṃ

Try it online!

HyperNeutrino

Posted 2017-11-15T15:31:51.847

Reputation: 26 575

2

Mathematica, 110 99 bytes

Max@#-Min@#&[#~FromDigits~2&/@Partition[s=Join@@Tuples[{0,1},4][[IntegerDigits@#+1]],Tr[1^s],1,1]]&


Try it online!

J42161217

Posted 2017-11-15T15:31:51.847

Reputation: 15 931

2

Retina, 96 89 bytes

.
@@@$&
@(?=@@[89]|@[4-7]|[2367])
_
T`E`@
\d
_
.
$&$'$`¶
O`
_
@_
+`_@
@__
s`(_+).*\W\1

_

Try it online! Somewhat slow, so link only includes a small test case. Edit: Saved 7 bytes thanks to @MartinEnder. Explanation:

.
@@@$&

Prefix three @s to each digit. (These represent the 0s of the BCD, but are golfier.)

@(?=@@[89]|@[4-7]|[2367])
_

Change the @s to _s (representing the 1s of the BCD) where appropriate.

T`E`@
\d
_

Fix up the last digit of the BCD.

.
$&$'$`¶

Generate all of the rotations.

O`

Sort them into ascending order.

_
@_
+`_@
@__

Convert them to unary.

s`(_+).*\W\1

_

Subtract the first from the last number, ignoring intermediate numbers, and convert to decimal.

Neil

Posted 2017-11-15T15:31:51.847

Reputation: 95 035

There's no need to use % for the binary to unary conversion and you can save a few more bytes by using other characters than 0 and 1 for binary: https://tio.run/##K0otycxL/P9fj0tRUVFFjUtRw95WUTHawjK2RjHaRNc8tibayNjMPFaTy5ErJME1QZErJgXI1ONSUVNRV0k4tI3LPwHIV3Tk0k5wVATSjlzFCRqO2pp6WjHhMYZcXI7//xsaAQA

– Martin Ender – 2017-11-16T21:41:35.223

@MartinEnder Oh, I think that dated from when I was trying and failing to use one of your binary conversion routines... – Neil – 2017-11-16T22:11:13.350

2

Ruby, 96 91 bytes

->n{r=""
n.digits.map{|d|r="%04b"%d+r}
s=r.chars.map{(r=r[1..-1]+r[0]).to_i 2}
s.max-s.min}

Try it online!

  • Saved 5 bytes thanks to displayname

Reinstate Monica -- notmaynard

Posted 2017-11-15T15:31:51.847

Reputation: 1 053

->n{r="" n.digits.map{|d|r="%04b"%d+r} s=r.chars.map{(r=r[1..-1]+r[0]).to_i 2} s.max-s.min} should be 91 bytes – displayname – 2017-11-15T22:50:12.267

@displayname Ha, yeah, you're right. Thank you – Reinstate Monica -- notmaynard – 2017-11-15T22:55:31.347

2

PHP, 156 153 bytes

<?foreach(str_split($argv[1])as$n)$s.=str_pad(decbin($n),4,0,0);for(;$i<$a=strlen($s);)$r[]=bindec(substr($s,$i).substr($s,0,$i++));echo max($r)-min($r);

Try it online!

Jo.

Posted 2017-11-15T15:31:51.847

Reputation: 974

2

Python 3, 141 bytes

def f(a):a=''.join([format(int(i),'#010b')[-4:]for i in str(a)]);b=[int(''.join(a[-i:]+a[:-i]),2)for i in range(len(a))];return max(b)-min(b)

Try it online

sonrad10

Posted 2017-11-15T15:31:51.847

Reputation: 535

2

Haskell, 130 bytes

r=foldl1
f x=max#x-min#x
f#x|s<-show x=r((+).(2*)).r f.take(sum$4<$s).iterate(drop<>take$1)$do d<-s;mapM(pure[0,1])[1..4]!!read[d]

Try it online!

Explanation / Ungolfed

Since we're going to use foldl1((+).(2*)) to convert from binary to decimal, we might as well not use maximum and minimum but rather foldl1 max (or same with min respectively) and use a short r = foldr1.

Now, let us define an operator f#x which converts x to BCD, generates all rotations, reduce these using f and convert it to decimal:

f # xs
  | s <- show xs
  = foldr1 ((+).(2*))                             -- convert from binary to decimal
  . foldr1 f                                      -- reduce by either max or min
  . take (4 * length s)                           -- only keep 4*length s (ie. all "distinct" rotations)
  . iterate (drop<>take $ 1)                      -- generate infinite list of rotations
  $ do d<-s; mapM (pure[0,1]) [1..4] !! read [d]  -- convert to BCD

Now it's only a matter of using this operator once with max and once with min and subtracting their results:

f x = max#x - min#x

ბიმო

Posted 2017-11-15T15:31:51.847

Reputation: 15 345

2

Japt -x, 20 bytes

®¤ùT4쬣ZéY ì2Ãn äa

Try it online!

Input as an array of digits.

Explanation:

®¤                      #Map each digit to base 2
  ùT4Ã                  #Pad each one to 4 places
      ¬                 #Join them to a single binary string
       ¬                #Split them to an array of single characters
        £      Ã        #For each index Y in that array:
         ZéY            # Get the array rotated Y times
             ì2         # Convert the array from binary to decimal
                n       #Sort the results
                  äa    #Get the absolute difference between each element
                        #Implicitly output the sum

Kamil Drakari

Posted 2017-11-15T15:31:51.847

Reputation: 3 461

1You can use the -x flag to save 2 bytes. – Oliver – 2018-12-14T00:23:34.987

120 bytes. – Oliver – 2018-12-17T20:27:27.767

1

Perl 5, 97 91 89 + 2 (-F) = 99 93 91 bytes

$a=sprintf"%04b"x@F,@F;@r=sort{$b<=>$a}map{oct"0b".($a=(chop$a).$a)}(@F)x4;say$r[0]-pop@r

Try it online!

Xcali

Posted 2017-11-15T15:31:51.847

Reputation: 7 671

1

Pyth, 24/26 bytes

s.+Smi.>Gd2l=Gsm.[\04.Bs

Takes input as a quoted string. 26 bytes if it needs to take input as an integer; append dz in that case.

Test Cases (input as strings, 24 bytes)

Test Cases (input as numbers, 26 bytes)

Steven H.

Posted 2017-11-15T15:31:51.847

Reputation: 2 841

1

J, 43 bytes

3 :'(>./-<./)#.(i.@#|."0 1]),}.#:8,"."0":y'

Try it online!

Sometimes tacit style makes things difficult. But there's probably a way to do it tacit style that's a lot more concise than this. I think I remember a better way to split a number to digits other than "."0@": but I can't seem to recall it...

Explanation

3 :'(>./-<./)#.(i.@#|."0 1]),}.#:8,"."0":y'
                                         y  the input (integer)
                                       ":   convert to string
                                   "."0     evaluate each char (split to digits)
                                 8,         prepend 8
                               #:           debase 2
                             }.             behead (remove the 8)
                            ,               ravel (flatten)
               (i.@#|."0 1])                create a list of rotations
                    |.    ]                   rotate the list
                      "0 1                    for each number on the left
                i.@#                          range 0 ... length - 1
             #.                             convert rotations back to base 10
    (>./-<./)                               max minus min

The prepending and removing 8 is to ensure that the right number of zeroes are present (J will reshape its arrays to be the size of their maximum length element, and 8 is 4 digits in binary so it is used).

cole

Posted 2017-11-15T15:31:51.847

Reputation: 3 526

1

APL(NARS), 34 chars, 68 bytes

{(⌈/-⌊/)2⊥¨{⍵⌽a}¨⍳≢a←∊⍉(4⍴2)⊤⍎¨⍕⍵}

some little test:

  h←{(⌈/-⌊/)2⊥¨{⍵⌽a}¨⍳≢a←∊⍉(4⍴2)⊤⍎¨⍕⍵}
  h 9752348061
1002931578825
  h 0
0

RosLuP

Posted 2017-11-15T15:31:51.847

Reputation: 3 036