integer max/min/abs etc in the math package

12,512 views
Skip to first unread message

ajray

unread,
Aug 1, 2011, 5:32:33 AM8/1/11
to golang-nuts
Is there any particular reason why there isnt integer versions of the
max/min/abs functions in the math package?

If thats by design I'm curious what the rationale is. And if not I'll
volunteer to do the patch myself.

~Alex

barnex

unread,
Aug 1, 2011, 6:29:39 AM8/1/11
to golang-nuts
I often need integer and/or float32 counterparts of the math
functions. If you are interested I would be happy to join a small
github project or alike to implement this.

-Arne.

John Asmuth

unread,
Aug 1, 2011, 8:21:36 AM8/1/11
to golan...@googlegroups.com
There's a version for float64, which is the type used by the math package.

To support all types, there'd need to be a version for int, int8, int32, int64, uint8, uint32, uint64, float32.

A generic solution would be ideal.

Alex Ray

unread,
Aug 1, 2011, 4:49:18 PM8/1/11
to golan...@googlegroups.com

Generics are difficult.  Either you end up defining special types with generic operations on them (a la pkg/sort) or you end up reflecting on yourself and burning a lot of performance and adding complexity.
At the worst case, all of them could be implemented and you have a more verbose library. 
Maybe the best method of getting feedback in this case is to submit the patch and see what they say. :-)

--alex

Florian Uekermann

unread,
Aug 1, 2011, 5:53:41 PM8/1/11
to golang-nuts
+1
as long as real generics aren't there, int64 should be the way to go I
guess, I would love to see integer functions in the math (or imath)
package.
gcd, pow, min, max, variants of mod...

On Aug 1, 10:49 pm, Alex Ray <alexjray.n...@gmail.com> wrote:
> Generics are difficult.  Either you end up defining special types with
> generic operations on them (a la pkg/sort) or you end up reflecting on
> yourself and burning a lot of performance and adding complexity.
> At the worst case, all of them could be implemented and you have a more
> verbose library.
> Maybe the best method of getting feedback in this case is to submit the
> patch and see what they say. :-)
>
> --alex

Johann Höchtl

unread,
Aug 2, 2011, 8:21:02 AM8/2/11
to golang-nuts


On Aug 1, 11:53 pm, Florian Uekermann <f...@uekermann-online.de>
wrote:
> +1
> as long as real generics aren't there, int64 should be the way to go I
> guess, I would love to see integer functions in the math (or imath)
> package.
> gcd, pow, min, max, variants of mod...
>

I would rather not see them implemented. First, they are trivial and
second, having them implemented might slightly shift the pressure for
generics, which I still consider a good thing for Go.

Florian Uekermann

unread,
Aug 2, 2011, 11:08:17 AM8/2/11
to golang-nuts
I strongly disagree.

> First, they are trivial and

That on its own is not a reason for not doing it.
Gcd is short and not difficult, but certainly not trivial for most
people. And it doesn't change the fact that it is convenient.

> second, having them implemented might slightly shift the pressure for
> generics, which I still consider a good thing for Go.

Why? There are approx. 5-8 funtions in math that make sense with
floating point and integer math. And even in those cases I would be
very surprised if there is a good generic way to implement them for
floats and ints. So why should implementation of integer math for
int64
alleviate "the pressure for generics"?

Don't get me wrong I feel that generics are needed too, but certainly
not
because the math package is missing integer math.

Blocking developement of something to wait for something else which
is by no means a precondition for the target in question for
"political"
reasons... ...best recipe for stalling developement.

That sounds a bit angry... ...I am not, I just don't like the
rationale
at all.

barnex

unread,
Aug 2, 2011, 4:41:07 PM8/2/11
to golang-nuts
I've started a github project "fmath", a float32 counterpart for the
math library (similarly, an "imath" package could be written for
integer functions).

The "portable" implementation is written in pure Go and simply uses
the standard math library, casting between float32s and float64s.
However, where possible I'm also providing assembly implementations.
They use single-precision machine instructions and should be faster.
Any help, especially on non-amd64 assembly is welcome! Many functions
still have to be implemented.

Refer github.com/barnex/fmath.

-Arne.

John Asmuth

unread,
Aug 2, 2011, 8:25:00 PM8/2/11
to golan...@googlegroups.com
+1

Thomas Bushnell, BSG

unread,
Mar 29, 2013, 1:51:53 PM3/29/13
to super...@gmail.com, golang-nuts
Getting abs right for floating point has subtlety (look at the implementation). Getting it right for integers is trivial. So just use <.


On Fri, Mar 29, 2013 at 9:44 AM, <super...@gmail.com> wrote:
Is there any recent news on this?

As a new go user, it was very surprising to me to discover that I have to convert my integer to and from a float64 in order to do a simple absolute value. In the end, I ended up implementing the integer version of abs myself, which defeats the whole point of the math package.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

peterGo

unread,
Mar 29, 2013, 3:31:54 PM3/29/13
to golan...@googlegroups.com, super...@gmail.com
Alex,

The question should be: can I easily add useful functions to Go?

From a suitable directory in your $GOPATH:

$ cd src
$ mkdir alex
$ mkdir alex/math
$ mkdir alex/math/int
$ cd alex/math/int

Create this Go package file in the directory.

$ cat int.go
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package int

// Abs returns the absolute value of x.
func Abs(x int) int {
    if x < 0 {
        return -x
    }
    return x
}

// Abs32 returns the absolute value of x.
func Abs32(x int32) int32 {
    if x < 0 {
        return -x
    }
    return x
}

// Abs64 returns the absolute value of x.
func Abs64(x int64) int64 {
    if x < 0 {
        return -x
    }
    return x
}
$

Create an int_test.go file; write and run some tests.

Install the math/int package.

$ go install math/int

Now you can easily obtain the absolute values of integers. For example,

package main

import (
    "alex/math/int"
    "fmt"
)

func main() {
    fmt.Println(int.Abs(-0), int.Abs(-0), int.Abs(42), int.Abs(-42))
    fmt.Println(int.Abs32(-0), int.Abs32(-0), int.Abs32(42), int.Abs32(-42))
    fmt.Println(int.Abs64(-0), int.Abs64(-0), int.Abs64(42), int.Abs64(-42))
}

Output:

0 0 42 42
0 0 42 42
0 0 42 42

That was easy.
 
Peter


On Friday, March 29, 2013 12:44:36 PM UTC-4, super...@gmail.com wrote:
Is there any recent news on this?

As a new go user, it was very surprising to me to discover that I have to convert my integer to and from a float64 in order to do a simple absolute value. In the end, I ended up implementing the integer version of abs myself, which defeats the whole point of the math package.

On Monday, August 1, 2011 5:32:33 AM UTC-4, Alex Ray wrote:

Stefan Nilsson

unread,
Mar 29, 2013, 5:28:24 PM3/29/13
to golan...@googlegroups.com, super...@gmail.com
I don't find this trivial. What should abs_int32(-1<<31) do? It can't return 1<<31 because that number can't be represented as an int32. Panic? Error? Something else?

dane

unread,
Mar 29, 2013, 6:29:57 PM3/29/13
to golan...@googlegroups.com, super...@gmail.com
Not that I am an expert, but I guess that has nothing to do with the abs function but with converting a constant to int32.

Stefan Nilsson

unread,
Mar 30, 2013, 6:19:56 AM3/30/13
to golan...@googlegroups.com, super...@gmail.com
The problem is that for signed integers in two's complement notation there are more negative numbers than positive ones. The smallest int32 is -1<<31, while the largest one is 1<<31 - 1.

Java's standard library "solves" the problem by making abs(-1<<31) return -1<<31:

"Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative."

C's standard library "solves" the problem by not defining the behavior of abs(-1<<31):

"Note that in two's compliment that the most maximum number cannot be represented as a positive number. The result in this case is undefined."

Both are terrible "solutions".

Dan Kortschak

unread,
Mar 30, 2013, 6:30:15 AM3/30/13
to Stefan Nilsson, golan...@googlegroups.com, super...@gmail.com
What is the alternative? When this happens in my code, I panic("weird integer").

Michael Jones

unread,
Mar 30, 2013, 11:06:32 AM3/30/13
to Dan Kortschak, Stefan Nilsson, golan...@googlegroups.com, super...@gmail.com
The finite precision integral arithmetic provided by computer hardware are not equivalent to the ideal integers of mathematics. Nor are the finite precision integral types of programming languages. If you are the kind of person who cares about this difference, or are solving a problem where this difference matters, then the obligation is to embrace the reality of finite precision integral arithmetic's operations and numbers.

What is different?

Integers are unbounded, numbers have minimum and maximum values. This means that adding one to the most positive number N, does not produce N+1 as with integers, but something special and unique to the world of computer hardware. In all computers it will produce a special signal, known as an overflow indication. This is the hardware telling us after every operation that the result of the finite-precision computer operation no longer matches the equivalent result in ideal integers. This signal is ignored in just about every computer programming language, and in those few where it can be accessed, it is disabled or ignored by programmers. 

In modern computers (two's complement machines) the result of this one special limit case for finite-precision addition is defined to be the most negative number. As has been motivated this thread, there is an asymmetry to these numbers that is important to understand. Here is the signed 8-bit number line:

 -256, -255, -254, ..., -2, -1, 0, 1, 2, ..., 254, 255

Much is magical about this that would not be the case in mathematics: 255+1 = -256, -256-1 = 255, 0 is not the center of the number line and most of all, that -(-256) = -256.

This last fact is what needs be embraced when computing the absolute value of a fixed-precision two's complement number: there is a number that does not have an absolute value. Since this is true (-256) then we cannot have an absolute value function that works as it would in the realm of ideal integers. This is not a failure of the finite approximation. It is just a way of knowing that you're past the edge so the approximation no longer applies. Unfortunately, since the overflow bit for addition and underflow bit for subtraction are ignored then dealing with this in higher level languages is tedious. Most people just don't bother; they employ a larger finite-precision integer. Calculations that encounter the 8-bit limits of 256+1 or -(-256) may never run up against the 64-bit equivalents: 9223372036854775807 + 1 and -(-9223372036854775808), but they might.

The intrusion of the finite limits on ideal arithmetic us much more severe and yet much less appreciated in the realm of multiplication. I wrote a long email about this here a year or two ago and won't repeat it all now, but this question shows the essential problem: which of the products i*j, where 1 <= i,j <= 255 are larger than 255 in ideal integers?


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.





--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

Kevin Gillette

unread,
Mar 30, 2013, 2:43:43 PM3/30/13
to golan...@googlegroups.com, super...@gmail.com
On Friday, March 29, 2013 10:44:36 AM UTC-6, super...@gmail.com wrote:
As a new go user, it was very surprising to me to discover that I have to convert my integer to and from a float64 in order to do a simple absolute value. In the end, I ended up implementing the integer version of abs myself, which defeats the whole point of the math package.

Keep in mind that, for programming in general (it's not just Go), converting integers to floating point and back, as a matter of convenience, is almost always a very bad idea. IEEE-754 64-bit floats (float64 in Go) can only accurately represent integers in the range [-2^53,2^53]. That means that all integer sizes from int8 to int32 can get away with using the math.Abs conversion trick, but int64 cannot.

As mentioned before, math.Abs exists because floats have special properties that need accounting for, such as NaN, infinity, and possibly negative 0, all of which ints don't have (so aside from slowing down the check by converting to and from float64, properties which couldn't possibly pertain to the value you're passing are being redundantly checked for).

One of the principles behind the design of the go stdlib is to not provide anything that the programmer can (and should be able to) trivially provide for themselves; integer absolute value is one of these things. For int, one implementation is literally:

func Abs(x int) int {
  if x < 0 {
    return -x
  }
  return x
}

I wrote that in less time than I would've spent starting up a browser, doing a search for 'golang Abs', and noticing that math.Abs only deals in float64, and my version certainly does a lot less redundant processing to arrive at the correct answer (and on amd64 deployments, actually _can_ arrive at the correct answer for all possible values).

@Michael Jones, @kortschak: what's the reason for wrapping minimum-value checks into an integer abs implementation? Just have it do the simplest thing (as in the above -- implicitly return the minimum int value when given the minimum int value) -- the calling application code only needs to be aware (if it cares) that a negative number will be returned when passed the minimum value, and can either check for that value before calling Abs, or check to see if the returned result is negative (which also handily indicates that the input was indeed the minimum value). Either way, it's the application's responsibility, not Abs, to make the distinction, and take appropriate behavior (which could be a panic, error return, decrement, etc., depending on needs)

Michael Jones

unread,
Mar 30, 2013, 3:54:28 PM3/30/13
to Kevin Gillette, golang-nuts, Andrew Kelley
No need to do the test in Abs(). I agree. But if it was me I'd want to remind people that AbsInt8(-128) will return -128, and so on. (I used 255 before and regret posting while half awake. ;-)

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Kevin Gillette

unread,
Mar 30, 2013, 4:39:11 PM3/30/13
to golan...@googlegroups.com, Kevin Gillette, Andrew Kelley
On Saturday, March 30, 2013 1:54:28 PM UTC-6, Michael Jones wrote:
No need to do the test in Abs(). I agree. But if it was me I'd want to remind people that AbsInt8(-128) will return -128, and so on. (I used 255 before and regret posting while half awake. ;-)

I'm sure someone somewhere would wonder why we don't have an AbsUint8 ;) 

Michael Jones

unread,
Mar 30, 2013, 4:43:35 PM3/30/13
to Kevin Gillette, golang-nuts, Andrew Kelley
;-)


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Dan Kortschak

unread,
Mar 30, 2013, 5:11:51 PM3/30/13
to Kevin Gillette, golan...@googlegroups.com, super...@gmail.com
I don't. But where I have abs functionality operating on integer values I make the check I described. Since I can see no sane way to deal with the weird number a panic seems the most reasonable approach.

Dan Kortschak

unread,
Mar 30, 2013, 5:34:24 PM3/30/13
to Kevin Gillette, golan...@googlegroups.com
I should clarify, there are a few places where a sign change is made to negative numbers in my code. In each of those places the most appropriate response was a panic. I don't think I have an exported Abs(int) int.

Tarmigan

unread,
Mar 30, 2013, 6:34:44 PM3/30/13
to Kevin Gillette, golang-nuts
On Sat, Mar 30, 2013 at 1:39 PM, Kevin Gillette <extempor...@gmail.com> wrote:
It's bit more complicated than AbsInt8 (you have you use "math/cmplx" in addition to "math") so I think there would be more of a case for including it in the standard library:


-Tarmigan

peterGo

unread,
Mar 31, 2013, 8:55:19 AM3/31/13
to golan...@googlegroups.com, Kevin Gillette
Dan,

I have an exported Abs(x int) int. I panic for invalid arguments.


// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package int

import "math"

// Integer limit values.
const (
    MaxInt   = int(^uint(0) >> 1)
    MinInt   = int(-MaxInt - 1)
    MaxInt32 = int32(math.MaxInt32)
    MinInt32 = int32(math.MinInt32)
    MaxInt64 = int64(math.MaxInt64)
    MinInt64 = int64(math.MinInt64)
)


// Abs returns the absolute value of x.
func Abs(x int) int {
    switch {
    case x >= 0:
        return x
    case x > MinInt:
        return -x
    }
    panic("math/int.Abs: invalid argument")

}

// Abs32 returns the absolute value of x.
func Abs32(x int32) int32 {
    switch {
    case x >= 0:
        return x
    case x > MinInt32:
        return -x
    }
    panic("math/int.Abs32: invalid argument")

}

// Abs64 returns the absolute value of x.
func Abs64(x int64) int64 {
    switch {
    case x >= 0:
        return x
    case x > MinInt64:
        return -x
    }
    panic("math/int.Abs64: invalid argument")
}

Peter

John Nagle

unread,
Mar 31, 2013, 2:39:46 PM3/31/13
to golan...@googlegroups.com
On 3/30/2013 2:11 PM, Dan Kortschak wrote:
> I don't. But where I have abs functionality operating on integer
> values I make the check I described. Since I can see no sane way to
> deal with the weird number a panic seems the most reasonable
> approach.

Math domain limits are a problem in a language without exceptions.
For floats, returning a propagating NaN sort of works. "int" lacks an
invalid value. So the options are ignore, panic, return an error
code, or set some global error flag.

John Nagle

Reply all
Reply to author
Forward
0 new messages