U
U
uvelichitel2014-12-16 15:48:20
go
uvelichitel, 2014-12-16 15:48:20

How to write very fast (let platform-specific) abs(x int32) in Go?

I am writing a number crusher. The speed of the operation is critical. abs() for int32 is not implemented in stdlib. This does not work (well, or there is not enough ability to implement it).
uint32(x) works, but what is there in general is not intuitive.
unsafe.Pointer() is taken so what? https://play.golang.org/p/ZAAJTv3sA_
On irc #go-nuts they said that the sign is exactly in the upper bit. Tell me how to get to it bitwise.
If without inventions to write
if x<0 {x=-x}; //and this is a shift check and two copies
, will the compiler just mask the sign without checks? For float64 in stdlib.math, this is actually done, but ...
The task is private - int32, GOOS/ARCH=linux/amd64

Answer the question

In order to leave comments, you need to log in

2 answer(s)
N
neolink, 2014-12-16
@uvelichitel

here is the implementation on go https://play.golang.org/p/zTe6pRwx0Y (based on "it doesn't work")

package main

import "fmt"

func abs(x int) int {
  m := x >> 31

  return (x + m) ^ m
}

func main() {
  fmt.Println(abs(-65580))
}

this compiles to:
01	MOVQ	$-65580,AX
02	MOVQ	AX,DX
03	SARQ	$31,AX
04	ADDQ	AX,DX
05	XORQ	AX,DX

here you can look at 2 canonical assembler versions for x86: www.strchr.com/optimized_abs_function
that is, the difference is only in replacing 02-03 with one cdq instruction , if you want to achieve 3 instructions - you can manually make an implementation in assembler, see the same math package for example .

D
druid3, 2015-01-02
@druid3

int32 is a fixed word length, bits are "numbered" without regard to endianness - it's hard to "miss" (:)) even on a different architecture. We overwrite the most significant bit (actually the sign) and voila. ... And the examples given by you (uvelichitel) are working, as neolink has already shown.
So it’s true, but the code of negative numbers is additional up to 2-x ... therefore we select the highest bit with a mask and cunningly dance with a tambourine also because there is no bitwise negation in go (!)
but in general you need

To get the number itself from the additional code... .

#include <stdlib.h>
#include <unistd.h>

int i32abs4training(int x)
{
    int m;

    m = 2*((x >> 31)&1) - 1; // negative or positive (invers)
 //   printf("bits in a integer word %i\n", sizeof(x)*8);

  return ~(m*x) + 1;
}

int main()
{
 printf ("%i\n", i32abs4training(-12));
 printf ("%i\n", i32abs4training(12));
 printf ("%i\n", i32abs4training(14));
 printf ("%i\n", i32abs4training(-32768));
}

The above code does not claim to be fast - it's just to show what the "fast" approach was derived from for golang, C and asm.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question