###Scala 785:
Let's start with a famous quote of Bjarne Stroustrup, the inventor of C++, which in his great wisdom told us:
Don't divide without necessity!
To make a submission to this fine question, we not only have to perform division - we have to implement it! Well - let's not talk about that.
object B{
val(l,o)=('1',"0")
type S=String
def n(v:S,c:S)=o*(c.size-v.size)+v
def g(n:S,m:S)=((n zip m)find(a=>a._1!=a._2)).getOrElse((l,'0'))._1==l
def a(x:S,y:S)=(((x zip y):\o)((n,m)=>{val s=Seq(m(0),n._1,n._2).filter(_==l).size
Seq("00","01","10","11")(s)}+m.tail))
def P(x:S,y:S)=t(a(n(x,y),n(y,x)))
def m(a:S,b:S)=(o/:a.zipWithIndex.filter(_._1==l).map(x=>b+o*(a.size-x._2-1)))(P)
def x(x:S,y:S)=t(s(x,y))
def s(x:S,y:S)=((x zip y):\o)((n,m)=>{val s=Seq(if(n._1==l)'0'else l,m(0),n._2).filter(_==l).size
Seq("01","00","11","10")(s)}+m.tail)
def M(a:S,b:S)=if(b==o)a else t(x(n(a,b),n(b,a)))
def d(n:S,m:S):S=if(g(n,m))P(D(M(n,m),m),"1")else o
def D(a:S,b:S)=t(d(n(a,b),n(b,a)))
def t(s:S)={val r=(s.substring(s.size-math.min(s.size,32))).replaceAll("^0*","")
if(r=="")o else r}
}
As usual, I have a less golfed version too, to explain 1 or 2 points (and this thread has much space left):
object BinArithmetic {
def normalize (v: String, cmp: String) = "0" * (cmp.size - v.size) + v
def ge(n:String, m:String)=((n zip m)find(a=>a._1!=a._2)).getOrElse(('1','0'))._1=='1'
def greaterEqual (a:String, b:String): Boolean = ge (normalize (a, b), normalize (b, a))
def i(s:String)=if(s=="0")"0"else trim32(j(s))
def j(s:String):String=if(s.size==0)""else{if(s(0)=='1')'0'else'1'}+j(s.tail)
def add (x:String, y: String): String =
(((x zip y) :\ "0")((b, a) => {
List (a(0), b._1, b._2).filter (_ == '1').size match {
case 0 => "00"
case 1 => "01"
case 2 => "10"
case 3 => "11"
}
}+a.tail))
def plus (a:String, b:String): String = {
trim32 (add (normalize (a, b), normalize (b, a)))
}
def mul (a:String, b: String): String =("0" /: a.zipWithIndex.filter (_._1 == '1').map (x=> b+ "0" * (a.size - x._2 - 1)))(plus)
def sub(x:String, y: String): String = trim32(s(x,y))
def s(x:String, y: String): String =
((x zip y) :\ "0")((b, ü) => {
List (if(b._1=='1')'0' else '1', ü(0), b._2).filter (_ == '1').size match {
case 0 => "01"
case 1 => "00"
case 2 => "11"
case 3 => "10"
}
}+ü.tail)
def minus (a:String, b:String): String = if (b=="0") a else {
trim32 (sub (normalize (a, b), normalize (b, a)))
}
def d(n:String,m:String):String=if(ge(n,m))plus(div(minus(n,m),m),"1")else "0"
def div (a:String, b:String): String = {
trim32 (d (normalize (a, b), normalize (b, a)))
}
def trim32 (s: String): String = {
val res = (s.substring (s.length - math.min (s.length, 32))).replaceAll ("^0*", "")
if (res == "") "0" else res
}
}
Half way through golfing and obfuscating the code I changed the methods add and s(ub) a bit. Later I recognized that I didn't used the methods i(nv) and j which handled inversing numbers - my research showed that you can inverse a number as binary string, you can add "1" and so sub (a, b) should theoretically be the same as add (add (a, inv(b)), "1") but in practice, it isn't. :)
There are 4 sorts of Methods:
- preparation (normalize (a,b)) for example, which takes tow numbers, and makes them equal long
- core calculation methods (add, sub, mul, div)
- wrapping methods, which usually take (a,b) and normalize the call to the calculation methods with similar names (plus, minus)
- finishing methods, which post process the result (trim32)
The root is the add method.
def a(x:S, y: S) = (((x zip y) :\ "0")((n, m) => {
val s=List (m(0), n._1, n._2).filter (_ == '1').size
List ("00", "01", "10", "11") (s)
}+m.tail))
:\ is the right-fold operator. x zip y produces the list of pairs (10), (01), (11) from "101", "011", combines it with the overrun of the last operation, starting with no such overrun 0, counts the 1s in the result and produces a micro String like "10" from it. The 0 gets the growing part of the output, while 1 is the new overrun. You learned that at elementary school, didn't you? Now you remember!
The mul - method is interesting:
def mul (a:String, b: String): String =
("0" /: a.zipWithIndex.filter (_._1 == '1').map (x=> b+ "0" * (a.size - x._2 - 1)))(plus)
From mul ("1010", "0110"), it takes a and zips with index ("1010"->0123 => 10, 01, 12, 03) filters those which are 1 in a: (10, 12) takes the b and adds (a.size=4 - (x._2=[0,2]) - 1) times a literal "0". 4-0-1 = 3, 4-2-1=1 => "0110"+"000", "0110"+"0". The result is put into the already defined plus operation, which is a normalized add.
div is just subtraction combined with addition:
def d (n:String, m:String):String=
if (greaterEqual (n,m)) plus (div (minus (n, m), m),"1") else "0"
if (n > m) then n/m = (n-m)/m + 1 else 0
if (8 > 3) 8/3 = (8-3)/3 + 1
if (5 > 3) 8/3 = (5-3)/3 + 1 + 1
since ! (2 > 3) 8/3 = 0 + 1 + 1
Sub is just similar implemented like add. Thanks to cyclic nature of ints, it doesn't really matter if the result is positive or negative.
Maybe I try the 2s-complement part later again.
Invocation
val ba = B
ba.plus ( "01010", "10101") // 11111
res412: String = 11111
ba.minus ( "11110", "01010") // 10100
res413: String = 10100
ba.mul ( "0010", "1000") // 10000
res414: String = 10000
ba.div ("1011010", "0010001") // 101
res415: String = 101