DEV Community

Keff
Keff

Posted on

[Challenge] Add numbers without (+-*/)

Time for another casual little challenge.

For this one there are only 2 rules:

  • you must add numbers a and b together
  • you must NOT use the +-*/ operators

Apart from that there are no more rules, and can be done with any language you want!

Pseudocode:

a = 2
b = 32

add(a, b) => 34
Enter fullscreen mode Exit fullscreen mode

Test:

add(a, b) == a + b
Enter fullscreen mode Exit fullscreen mode

Have fun! Let's see what you come up with!

Top comments (30)

Collapse
 
shekohex profile image
shekohex
const fn add<const A: usize, const B: usize>() -> usize {
    struct _Add<const A: usize, const B: usize> {
        _a: [u8; A],
        _b: [u8; B],
    }
    core::mem::size_of::<_Add<A, B>>()
}

#[test]
fn it_works() {
    assert_eq!(add::<40, 2>(), 42);
}
Enter fullscreen mode Exit fullscreen mode

Compile time execution goes brrrrrr 😂

Here is the full code with other solutions: https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=3fd17ceb138f1e2c230987bd93d93f25

Collapse
 
thedenisnikulin profile image
Denis

Rust gang lesssgooo

Collapse
 
nombrekeff profile image
Keff

Nice, that's really interesting! I like how the compiler replaces the Iterator example with a + b lol 🤣

Collapse
 
shekohex profile image
shekohex

Crazy!
(for anyone wonder what iterators, check out the rust playground link I've posted, there is other solution that uses iterators instead of const generics)

Collapse
 
pyrsmk profile image
Aurélien Delogu

Can you explain the trick with size?

Collapse
 
shekohex profile image
shekohex

The memory size of the struct _Add here would be the size of _a and _b combined, in other words for any type T and length of n, [T; n] has the size of n * size_of::<T>(), and since here T is u8 and its size is just 1 byte; hence [u8; n] is just n bytes. Using this; the size of _Add would be the size of [u8; A] (A bytes) and the size of [u8; B] (B bytes); will result in total is A+B bytes.

Thread Thread
 
pyrsmk profile image
Aurélien Delogu

Yes but this is where I'm lost. Wouldn't be the returned value 2 in every case?

Thread Thread
 
shekohex profile image
shekohex

No, in the test case, A = 40 means [0u8; 40] that also means 40 bytes, and B = 2 which is [0u8; 2] that's 2 bytes, which is total of 42 bytes.

Thread Thread
 
pyrsmk profile image
Aurélien Delogu • Edited

Ah indeed, thanks! I misunderstood the syntax.

edit : that's a really smart solution btw, thanks for sharing

Collapse
 
coderduck profile image
duccanhole
function add(a, b)
{
    if (b == 0)
        return a;
    else
        return Add(a ^ b, (a & b) << 1);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
naveennamani profile image
naveennamani • Edited

Stop using if else - some dev.to author

Thats a nice logical solution

Collapse
 
nombrekeff profile image
Keff

Wise solution 😜

Collapse
 
konung profile image
konung

Crystal or Ruby

def add(a, b)
  while b != 0
    carry = a & b
    a = a ^ b
    b = carry << 1
  end
  return a
end
Enter fullscreen mode Exit fullscreen mode
Collapse
 
armousness profile image
Sean Williams

I spent an unfortunate amount of time on this...

fn add(a: u32, b: u32) -> u32 {
    let mut carry = false;
    let mut result = 0;
    for i in 0..32 {
        let mask = 1 << i;
        let a_in = (a & mask) > 0;
        let b_in = (b & mask) > 0;
        let s =
            match (a_in, b_in, carry) {
                (false, false, true) => 1,
                (false, true, false) => 1,
                (true, false, false) => 1,
                (true, true, true) => 1,
                _ => 0,
            } << i;
        result = result | s;
        carry =
            match (a_in, b_in, &carry) {
                (false, true, true) => true,
                (true, false, true) => true,
                (true, true, false) => true,
                (true, true, true) => true,
                _ => false,
            };
    }
    result
}

fn main() {
    let a = 10521;
    let b = 830127;
    println!("the usual algorithm: {} + {} = {}", a, b, a + b);
    println!("the funky algorithm: {} + {} = {}", a, b, add(a, b));
}
Enter fullscreen mode Exit fullscreen mode

Output:

the usual algorithm: 10521 + 830127 = 840648
the funky algorithm: 10521 + 830127 = 840648
Enter fullscreen mode Exit fullscreen mode

This currently only works on unsigned integers. I don't feel like spending the time now to remember how two's complement works.

Collapse
 
armousness profile image
Sean Williams

Though I guess I'll be a bit more pedantic with this one: for i in 0..32 smuggles in some integer addition. So here's the set theoretic implementation, which has—less reliance on plus signs:

#[derive(Debug)]
enum Num {
    S(Box<Num>),
    Z,
}

fn s(n: Num) -> Num {
    Num::S(Box::new(n))
}

fn z() -> Num {
    Num::Z
}

fn set_add(a: Num, b: Num) -> Num {
    let mut result = a;
    let mut work = b;
    loop {
        match work {
            Num::S(next) => {
                result = s(result);
                work = *next;
            },
            Num::Z => return result,
        }
    }
}

fn main() {
    let a = s(s(s(z()))); // i.e., 3
    let b = s(s(s(s(s(z()))))); // i.e., 5
    println!("3 + 5 = {:?}", set_add(a, b));
}
Enter fullscreen mode Exit fullscreen mode

Output:

3 + 5 = S(S(S(S(S(S(S(S(Z))))))))
Enter fullscreen mode Exit fullscreen mode

Z means zero, and S means increment. So this is zero incremented eight times.

Collapse
 
object_required profile image
Nikolai Kim

Thank you for the challenge, I finally got into WebAssembly 🎉

async function makeAdd() {
  /*
   * (module
   *   (func $add (;0;) (export "add") (param $var0 f64) (param $var1 f64) (result f64)
   *     local.get $var0
   *     local.get $var1
   *     f64.add
   *   )
   * )
   */
  const response = await fetch("data:application/octet;base64,AGFzbQEAAAABBwFgAnx8AXwDAgEABwcBA2FkZAAACgkBBwAgACABoAs=")
  const buffer = await response.arrayBuffer()
  const { instance } = await WebAssembly.instantiate(buffer)

  return instance.exports.add
}

;(async function () {
  const add = await makeAdd()

  for (var a = -1; a <= 1; a += 1) {
    for (var b = -1; b <= 1; b += 1) {
      var s = add(a, b)
      var ok = s === a + b

      console[ok ? 'info' : 'warn'](`${ok ? '' : ''} add(${a}, ${b}) = ${s}`)
    }
  }
}())
Enter fullscreen mode Exit fullscreen mode
Collapse
 
pyrsmk profile image
Aurélien Delogu

Here's another, more serious, attempt (still in Ruby) :

def add(a, b)
  (-a...b).size
end
Enter fullscreen mode Exit fullscreen mode

Some explanations : in Ruby 0..10 is called a range. It is really useful to make arbitrary loops or splice an array, for example. Simply, a range is a suite of values. The syntax I used here is 0...10 (note the three dots) which is an exclusive range : the suite of values goes from 0 to 9. So the trick is to have a range going from -a to b and excluding b because 0 is included in the suite.

Collapse
 
naveennamani profile image
naveennamani
a.__add__(b)
Enter fullscreen mode Exit fullscreen mode

In python

Collapse
 
pyrsmk profile image
Aurélien Delogu

Nice cheat :p

Collapse
 
pyrsmk profile image
Aurélien Delogu • Edited

This is clearly cheating, but here we go with a Ruby solution :D

def add(a, b)
  [a, b].sum
end
Enter fullscreen mode Exit fullscreen mode
Collapse
 
nombrekeff profile image
Keff

Hahahah true xD if we stick to the rules yup... but I think I'll pass this one. I guessed there would be some languages that had built-in methods like this! What's the language BTW?

Collapse
 
pyrsmk profile image
Aurélien Delogu

Ruby and, by extension, Crystal.

Collapse
 
domedev94 profile image
domedev94
$a = 2;
$b = 32;
add($a,$b);

function add($n1,$n2){
    return count(array_merge(array_fill(0,$n1,"a"),array_fill(0,$n2,"b")));
}

Enter fullscreen mode Exit fullscreen mode
Collapse
 
nombrekeff profile image
Keff

Nice one!! I also thought of this solution!!! Not very scalable but cool nonetheless

Collapse
 
lexlohr profile image
Alex Lohr
const add = (a, b) => Array(a).fill(0).concat(Array(b).fill(0)).length
Enter fullscreen mode Exit fullscreen mode
Collapse
 
lexlohr profile image
Alex Lohr
const add = (a, b) => `${' '.repeat(a)}${' '.repeat(b)}`.length
Enter fullscreen mode Exit fullscreen mode
Collapse
 
migsarnavarro profile image
Migsar Navarro

js

const toArr = x => Array.from({ length: x });
const add = (a,b) =>  [...toArr(a), ...toArr(b)].length

add(2, 32); // return 34;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jonrandy profile image
Jon Randy 🎖️

Dangerous one:

const add = (a,b)=>eval(`${a}${String.fromCharCode(43)}${b}`)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited
const add=(a,b,c)=>{for(;b;c=a&b,a=a^b,b=c<<1);return a}
Enter fullscreen mode Exit fullscreen mode

A bit shorter (if you don't mind polluting namespace):

const add=(a,b)=>{for(;b;c=a&b,a=a^b,b=c<<1);return a}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
nombrekeff profile image
Keff

It kinda is nasty 🤣 I like it though