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!

Discussion (31)

Collapse
shekohex profile image
Shady Khalifa
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
pyrsmk profile image
Aurélien Delogu

Can you explain the trick with size?

Collapse
shekohex profile image
Shady Khalifa

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
Shady Khalifa

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 on

Ah indeed, thanks! I misunderstood the syntax.

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

Collapse
thedenisnikulin profile image
Denis

Rust gang lesssgooo

Collapse
nombrekeff profile image
Keff Author

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

Collapse
shekohex profile image
Shady Khalifa

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
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 on

Stop using if else - some dev.to author

Thats a nice logical solution

Collapse
lukeshiru profile image
Luke Shiru

I mean, it looks cuter without if or return:

const add = (a, b) => (b === 0 ? a : add(a ^ b, (a & b) << 1));
Enter fullscreen mode Exit fullscreen mode
Collapse
nombrekeff profile image
Keff Author

Wise solution 😜

Collapse
lukeshiru profile image
Luke Shiru • Edited on

Here's a really nasty one:

const add = (...args) => args.flatMap(length => Array.from({ length })).length;
Enter fullscreen mode Exit fullscreen mode

Cheers!

PS: Never do this. Is disgusting and it doesn't even add float numbers

Collapse
nombrekeff profile image
Keff Author

It kinda is nasty 🤣 I like it though

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
yaruson 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 • Edited on

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 Author

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
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
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 Author

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
jonrandy profile image
Jon Randy

Dangerous one:

const add = (a,b)=>eval(`${a}${String.fromCharCode(43)}${b}`)
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 • Edited on
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