15
\$\begingroup\$

Your task is pretty simple. Given two floats, bitwise xor the binary representation of them, and output that as a float.

For example,

Normal: 16.7472 ^ 123.61 = 7.13402e-37
Binary: 01000001100001011111101001000100 ^ 01000010111101110011100001010010 = 00000011011100101100001000010110

Normal: 2.2 ^ 4.4 = 1.17549e-38
Binary: 01000000000011001100110011001101 ^ 01000000100011001100110011001101 = 00000000100000000000000000000000

Normal: 7.898 ^ 3.4444 = 1.47705e-38
Binary: 01000000111111001011110001101010 ^ 01000000010111000110101001111111 = 00000000101000001101011000010101

Restrictions/clarifications:

\$\endgroup\$
  • 2
    \$\begingroup\$ Does Boolean list count as a convenient method? \$\endgroup\$ – Adám Sep 15 at 14:11
  • 23
    \$\begingroup\$ "binary representation" of a float is extremely ambiguous. You'll need to define which representation you're using. There are an infinite number of representations, including the finite number already used by life on this planet, some being more popular than others, such as IEEE 754 \$\endgroup\$ – Reversed Engineer Sep 16 at 10:07
  • 7
    \$\begingroup\$ This question would be more interesting as "xor the values" rather than "xor the representations". The latter is of course identical to "xor two 32-bit integers" in any language that lacks a type system or admits type punning, and thus is pretty boring... \$\endgroup\$ – R.. Sep 16 at 14:33
  • 5
    \$\begingroup\$ Do we have to handle infinity, subnormals, or negative 0, as either input or output? \$\endgroup\$ – Grimy Sep 16 at 16:24
  • 3
    \$\begingroup\$ @Mark: No, as written the question is just about xor'ing their representations, whatever those representations are. The result is dependent on the floating point format but the algorithm is always a single xor instruction on the representation, which is pretty boring. \$\endgroup\$ – R.. Sep 17 at 1:43

18 Answers 18

53
\$\begingroup\$

x86-64 machine code, 4 bytes

0f 57 c1 c3

In assembly:

xorps xmm0, xmm1
ret

This is a callable function that takes two floats or doubles as arguments (in xmm0 and xmm1) and returns a float or double (in xmm0).

That matches the calling conventions of both Windows x64 and the x86-64 SysV ABI, and works for floats as well as doubles. (They're passed / returned in the low 4 or 8 bytes of XMM registers).

\$\endgroup\$
12
\$\begingroup\$

C++ (gcc), 74 32 bytes

#define f(x,y)*(int*)x^=*(int*)y

Try it online!

I haven’t previously golfed in C++ so am grateful to all those who helped halve the size of the code! A macro which takes pointers to two floats as its arguments and modified the first to return the result.

Thanks to @12Me1 for saving 2 bytes and @Arnauld for saving 4! Thanks to @Nishioka for saving another 14, @Neil a further 6 and @AZTECCO and @Nishioka another 11! Thanks to @PeterCordes for saving 5 bytes!

\$\endgroup\$
  • 1
    \$\begingroup\$ You can remove the linebreaks to save 2 chars, and this also works in C \$\endgroup\$ – 12Me21 Sep 15 at 16:40
  • 1
    \$\begingroup\$ You can save 4 more bytes with z=*(int*)x^*(int*)y;. \$\endgroup\$ – Arnauld Sep 15 at 16:46
  • 1
    \$\begingroup\$ With gcc extensions, 54 bytes: #define f(x,y)({int z=*(int*)x^*(int*)y;*(float*)&z;}) \$\endgroup\$ – Nishioka Sep 15 at 18:34
  • 2
    \$\begingroup\$ Since you're using pointers, is it legal to use one of the inputs as the output? If so, you could write (*(int*)x^=*(int*)y). \$\endgroup\$ – Neil Sep 15 at 18:47
  • 1
    \$\begingroup\$ Taking into consideration @Neil's suggestion it would get to 48 bytes: #define f(x,y)({*(int*)x^=*(int*)y;*(float*)x;}) \$\endgroup\$ – Nishioka Sep 15 at 19:00
9
\$\begingroup\$

ARM Thumb Machine Code, 6 4 Bytes

48 40 70 47

In assembly:

EORS R0, R1 ; Exclusive Or of the first two params, store result in the return register
BX LR       ; Branch to the value stored in the Link Register (Return address)

Under the standard Arm calling convention, the first two parameters are passed in the registers R0 and R1, results are returned in R0, and LR holds the return address. Assuming you're using the soft float ABI with 32 bit floats, this will perform the desired operation in 4 bytes.

-2 bytes thanks to Cody Gray

\$\endgroup\$
  • 2
    \$\begingroup\$ Would it be possible to use EORS r0, r1 instead, in order to save 2 bytes? That's only a 2-byte instruction (48 40), compared to your 4-byte EOR. You're already targeting Thumb, so this should work fine, as far as I can see. The only difference is it updates status flags, but you don't care about that side effect in this case. \$\endgroup\$ – Cody Gray Sep 17 at 0:31
  • 2
    \$\begingroup\$ You should specify that this is using the soft-float ABI which passes FP args in integer registers, not VFP / NEON s0 and s1. \$\endgroup\$ – Peter Cordes Sep 17 at 7:30
6
\$\begingroup\$

Python 3 + numpy, 75 59 bytes

lambda x,y:(x.view("i")^y.view("i")).view("f")
import numpy

Try it online!

Defines a lambda which takes two numpy float32 arrays as its arguments and returns a numpy float32 array.

Thanks to @ShadowRanger for saving 14 bytes, and Joel a further 2!

If the import can be dropped (since my lambda itself calls methods on numpy objects rather than any base numpy functions), I could save a further 13 bytes. I’m uncertain on this from the code golf standard rules.

\$\endgroup\$
  • \$\begingroup\$ It's shorter than Jelly and Ruby answers. Nice! \$\endgroup\$ – Eric Duminil Sep 17 at 9:06
  • \$\begingroup\$ You can shave off 27 bytes (dropping it to 48 bytes) by removing the import entirely (just assume the caller passed you numpy.float32s so you can use their methods) and replacing both int32 uses with 'i' and the float32 usage with 'f'; the dtype parameter can be a string which gets converted to the real dtype for you, and conveniently, 'i' and 'f' are legal ways to make those dtypes, which removes the need for the function to import numpy stuff into its namespace at all. Not sure if it's Code Golf legal to remove the import but still assume numpy inputs... \$\endgroup\$ – ShadowRanger Sep 17 at 19:41
  • \$\begingroup\$ I thought the imports had to be included, but I’m not sure. Thanks for the tip re the dtypes! \$\endgroup\$ – Nick Kennedy Sep 17 at 19:44
  • \$\begingroup\$ @NickKennedy: Yeah, if the import is required, it only saves 8 bytes (two each from int32 to 'i', four from float32 to 'f'), but that's still something. If the import is strictly required, you could just change it to import numpy to assert the package exists, without using from numpy import* to extract names from it. That would get you another six bytes, down to 61 bytes total. \$\endgroup\$ – ShadowRanger Sep 17 at 19:46
6
\$\begingroup\$

Jelly + numpy, 89 77 bytes

“(F(“I^F(“IvF).item()”;"F“¢lẒṾ:/²)Ɓɱ¡vẠ⁷5Rʠ¡7ɼṆṪ{ė4¶Gẉn`¡Ð}ṫȥṄo{b»Ḳ¤¹ṣḢ}jʋƒŒV

Try it online!

Has the dubious honour of being longer than the Python 3 code it reproduces, largely because of the need to convert to/from numpy objecte and the fact that numpy isn’t loaded by Jelly so the __import__() built-in has to be used.

A monadic link taking the two floats as a list as its argument and returning a float.

Evaluates the following Python 3 code:

(__import__('numpy').float32(x).view("i")^__import__('numpy').float32(y).view("i")).view(__import__('numpy').float32).item()

where x and y are substituted with the input.

\$\endgroup\$
5
\$\begingroup\$

APL (Dyalog Unicode), 14 bytesSBCS

Full program. Prompts for 1-column matrix of two IEEE 754 64-bit floating-point numbers (binary64) from stdin. Prints one such number to stdout.

645⎕DR≠⌿11⎕DR⎕

Try it online!

 prompt (numbers that collapse to non-floats can be forced into floats with the function ⊃⊢⎕DR⍨645,⍨⎕DR)

11⎕DR convert to 1-bit Binary (1) Data Representation (2-row, 64-column matrix)

≠⌿ vertical XOR reduction

645⎕DR convert to 64-bit float (5) Data Representation (single number)

\$\endgroup\$
4
\$\begingroup\$

VAX BASIC (later VMS BASIC, then Compaq Basic), 11 bytes

H = F XOR G

Seems a bit silly to me, obviously, older languages will do better because they didn't worry abut strong-typing issues as much.

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to the site and nice first answer! I've edited out what appears to be an extraneous header, but if not feel free to edit it back in, along with any accompanying information \$\endgroup\$ – caird coinheringaahing Sep 16 at 14:20
2
\$\begingroup\$

C# (Visual C# Interactive Compiler), 92 bytes

x=>BitConverter.Int32BitsToSingle(x.Aggregate(0,(a,b)=>a^BitConverter.SingleToInt32Bits(b)))

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ You could use unsafe code for this, though I'm not sure if the "unsafe" keyword should affect the bytecount or not. \$\endgroup\$ – negative seven Sep 15 at 18:41
2
\$\begingroup\$

Octave, 59 bytes

@(a,b)(t=@typecast)(bitxor(t(a,u='int32'),t(b,u)),'single')

Try it online!

Typecast is the MATLAB/Octave way of casting without changing the underlying bits. This is required because bitxor only works on integers. No idea why they never implemented floating point numbers, even though you can explicitly specify the AssumedType as a third argument to bitxor. I guess the only use is recreational programming.

\$\endgroup\$
  • \$\begingroup\$ Bitwise stuff on FP bit patterns is useful in assembly language to do things with the sign bit, or rarely to stuff an integer into the exponent field as part of an exp() implementation. But I assume Octave already has functions/operators for copysign and negation. And they don't care about micro-optimizations like using AND (with a constant mask) then XOR to conditionally flip the sign of one value based on the sign of another. In a real optimization project in asm (actually C with AVX intrinsics) I have used XOR of floats then looking at the sign bit to avoid cmp against zero. \$\endgroup\$ – Peter Cordes Sep 17 at 7:36
2
\$\begingroup\$

Perl 5 -p, 31 27 bytes

-4 bytes thanks to Grimy

$\=unpack f,$a^=pack f,$_}{

Try it online!

\$\endgroup\$
2
\$\begingroup\$

MATL, 10 bytes

4Z%Z}Z~9Z%

Try it online!

Splitting with Z} was shorter than taking two inputs ,4Z%]

\$\endgroup\$
2
\$\begingroup\$

C, 23 bytes

f(int*x,int*y){*x^=*y;}

Try it online!

This might be a bit shifty; it takes the pointers to floats as pointers to ints.

However, it does work (this is C after all).

This takes advantage of acceptable input by taking a pointer to the variable and modifying it in-place. No (usable) value is returned.

\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js),  105  101 bytes

Shorter Node version suggested by @Neil
Saved 4 more bytes thanks to @ShieruAsakoto

Takes input as (x)(y).

x=>y=>(v=Buffer(4),v.writeInt32LE((g=n=>v.writeFloatLE(n)&&v.readInt32LE())(x)^g(y)),v.readFloatLE())

Try it online!


JavaScript (ES6), 115 bytes

Takes input as an array of 2 floats.

a=>(v=new DataView(new ArrayBuffer(4))).getFloat32(v.setUint32([x,y]=a.map(n=>v.getUint32(v.setFloat32(0,n))),x^y))

Try it online!

\$\endgroup\$
  • \$\begingroup\$ FYI Node's Buffer saves a few bytes: a=>(v=new Buffer(4),[x,y]=a.map(n=>v.writeFloatLE(n)&&v.readInt32LE()),v.writeInt32LE(x^y),v.readFloatLE()). \$\endgroup\$ – Neil Sep 15 at 18:57
  • \$\begingroup\$ @Neil Thanks! (saved 2 more bytes by using a function instead of map) \$\endgroup\$ – Arnauld Sep 15 at 21:50
  • 1
    \$\begingroup\$ Dropping the new in new Buffer(4) should also work iirc \$\endgroup\$ – Shieru Asakoto Sep 19 at 14:36
1
\$\begingroup\$

Wolfram Mathematica, 50 bytes

BitXor@@(FromDigits[RealDigits[#,2,32,0][[1]],2]&)

Although I strongly suspect that this could be more golfed, the two extra arguments in RealDigits function seem to be necessary for getting a correct result.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Lua, 73 bytes

a,b=('II'):unpack(('ff'):pack(...))print((('f'):unpack(('I'):pack(a~b))))

Try it online!

This code assumes 4-bytes unsigned integers and floats which is configuration on tio.run. Run as full program with input as arguments.

\$\endgroup\$
1
\$\begingroup\$

Ruby, 78 67 bytes

-11 bytes thanks to @grawity.

->x{[x.pack("gg").unpack("NN").inject(&:^)].pack(?N).unpack(?g)[0]}

Try it online!

Input is an array of two floats.

\$\endgroup\$
  • \$\begingroup\$ x.map{|v|[v].pack(?g).unpack(?N)[0]}x.pack("gg").unpack("NN") \$\endgroup\$ – grawity Sep 18 at 12:32
  • \$\begingroup\$ @grawity: Awesome, thank you very much! The code is still longer than in Python, though. :-/ \$\endgroup\$ – Eric Duminil Sep 18 at 13:35
1
\$\begingroup\$

Java (JDK), 109 76 bytes

(a,b)->Float.intBitsToFloat(Float.floatToIntBits(a)^Float.floatToIntBits(b))

Try it online!

Been a while since I golfed in Java and I'm not certain if I need the declaration on the LHS as part of the byte count? If it used DoubleBinaryOperator the LHS would be shorter, but the RHS would have to use Double.doubleToLongBits and Double.longBitsToDouble, so that's actually longer.

Thanks to Neil for a substantial savings on the byte count!

\$\endgroup\$
  • 1
    \$\begingroup\$ IIRC you don't even need the assignment as part of the byte count, only as part of any test suite you might include in your Try it online! header. \$\endgroup\$ – Neil Sep 18 at 12:37
  • \$\begingroup\$ @Neil Thank you! That makes a big difference! \$\endgroup\$ – David Conrad Sep 18 at 18:01
0
\$\begingroup\$

Clean, 36 bytes

f::!Real!Real->Real
f _ _=code{xor%}

Try it online!

Thankfully the Real and Int types are the same sizes on 64-bit platforms...
Unfortunately requires a complete signature otherwise the graph turns into a pretzel and everything segfaults.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.