New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

math: add Round #20100

Closed
DavidR91 opened this Issue Apr 24, 2017 · 38 comments

Comments

Projects
None yet
@DavidR91

DavidR91 commented Apr 24, 2017

What version of Go are you using (go version)?

1.8

What did you expect to see?

A rounding method for floats in the standard library

What did you see instead?

There is no standard library method for rounding a float64 to int/int32

I would like to see the lack of this method perhaps reconsidered: I think I understand why it was originally omitted (lots of different methods can be used: implement it as per your requirements rather than expecting a silver bullet in the stdlib)

But, the result of this actually seems to have been that this method just gets banded around by copy-and-pasting. Lots of projects duplicate exactly the same method over-and-over, and many suggestions (e.g. stackoverflow answers) contain inaccurate or flawed rounding methods - some of which may well be making their way into production apps.

Personally, I think it would make sense for the stdlib to contain the most primitive/straightforward rounding method possible (e.g. the +/- 0.5 method as seen in Kubernetes) and if something more in-depth is required, it then becomes an exercise for the implementer

Original discussions:

Implement it in a library

An obvious counterargument is that rather than duplicating this method, just expose it in a community/third party library which projects can just consume.

You could certainly make a positive argument for establishing a full library of math routines that perhaps offers this functionality with a multitude of rounding modes (probably already exists?). My argument against this it that a third-party component should not be necessary for the most basic implementation of rounding: it should be the go-to for advanced mathematics requirements, not beginner-level math.

Additionally, the same arguments could be levelled at many core pieces of functionality inside Go itself (if you make this point, you have to consider how kind of absurd it is that zlib is deemed integral to the standard library, but implementing the most basic of rounding methods is not)

Overall

I would just really appreciate seeing this omission reconsidered. If it is a question of not wanting to decide which rounding method is included, I would very strongly suggest that just a trivial/basic implementation is added (if acceptable) so that this functionality is not constantly duplicated in projects

As per the above: if a user needs very specific requirements / rounding modes, that should be the jumping off point for implementing your own. But the simplest + dumbest possible rounding should be part of the language IMO

@bradfitz bradfitz changed the title from math: reconsider the lack of a standard library rounding function for float64 to proposal: math: reconsider the lack of a standard library rounding function for float64 Apr 24, 2017

@gopherbot gopherbot added this to the Proposal milestone Apr 24, 2017

@gopherbot gopherbot added the Proposal label Apr 24, 2017

@slrz

This comment has been minimized.

Show comment
Hide comment
@slrz

slrz Apr 25, 2017

There is no standard library method for rounding a float64 to int/int32

No, it's built into the language instead and rounds towards zero. You're proposing to add another one that rounds half away from zero. Yet, you're saying that when the choice of rounding mode matters, you should probably go and implement your own.

slrz commented Apr 25, 2017

There is no standard library method for rounding a float64 to int/int32

No, it's built into the language instead and rounds towards zero. You're proposing to add another one that rounds half away from zero. Yet, you're saying that when the choice of rounding mode matters, you should probably go and implement your own.

@DavidR91

This comment has been minimized.

Show comment
Hide comment
@DavidR91

DavidR91 Apr 25, 2017

No, it's built into the language instead and rounds towards zero.

You're proposing to add another one that rounds half away from zero.

It's not really 'another one' at all. The fact you get floor by casting one type to another is an indirect result of truncation, I think it is quite a stretch to say it's built in rounding.

'Round half up' / away from zero is the intuitive concept of 'rounding' that most people expect/want 99% of the time.

DavidR91 commented Apr 25, 2017

No, it's built into the language instead and rounds towards zero.

You're proposing to add another one that rounds half away from zero.

It's not really 'another one' at all. The fact you get floor by casting one type to another is an indirect result of truncation, I think it is quite a stretch to say it's built in rounding.

'Round half up' / away from zero is the intuitive concept of 'rounding' that most people expect/want 99% of the time.

@cznic

This comment has been minimized.

Show comment
Hide comment
@cznic

cznic Apr 25, 2017

Contributor

'Round half up' / away from zero is the intuitive concept of 'rounding' that most people expect/want 99% of the time.

The only rounding need is trunc(f+0.5), ie. away from neg inf. I see nothing intuitive on changing the direction of the rounding for negative numbers.

Look at all the possibilities at Wikipedia.

Contributor

cznic commented Apr 25, 2017

'Round half up' / away from zero is the intuitive concept of 'rounding' that most people expect/want 99% of the time.

The only rounding need is trunc(f+0.5), ie. away from neg inf. I see nothing intuitive on changing the direction of the rounding for negative numbers.

Look at all the possibilities at Wikipedia.

@DavidR91

This comment has been minimized.

Show comment
Hide comment
@DavidR91

DavidR91 Apr 25, 2017

The only rounding need is trunc(f+0.5), ie. away from neg inf. I see nothing intuitive on changing the direction of the rounding for negative numbers.

I am aware of the various different rounding modes - and if you disagree with what I consider intuitive, that's fair.

But my point with this proposal was that I suspected the quantity of potential modes was the blocker for considering + implementing any round method in stdlib. I wanted to make it simpler to have it considered by limiting the scope to a very common + well understood mode (e.g. shared also by C99's roundf)

If the feedback is simply that lots of modes have to be supported in order for this proposal to be considered, that's fine - but obviously it is a significant amount of work to write + document and have unit tests for a number of different rounding modes (and therefore makes the proposal less likely to be considered)

DavidR91 commented Apr 25, 2017

The only rounding need is trunc(f+0.5), ie. away from neg inf. I see nothing intuitive on changing the direction of the rounding for negative numbers.

I am aware of the various different rounding modes - and if you disagree with what I consider intuitive, that's fair.

But my point with this proposal was that I suspected the quantity of potential modes was the blocker for considering + implementing any round method in stdlib. I wanted to make it simpler to have it considered by limiting the scope to a very common + well understood mode (e.g. shared also by C99's roundf)

If the feedback is simply that lots of modes have to be supported in order for this proposal to be considered, that's fine - but obviously it is a significant amount of work to write + document and have unit tests for a number of different rounding modes (and therefore makes the proposal less likely to be considered)

@cznic

This comment has been minimized.

Show comment
Hide comment
@cznic

cznic Apr 25, 2017

Contributor

I am aware of the various different rounding modes - and if you disagree with what I consider intuitive, that's fair.

FTR, in my post the crucial 'I' before 'need' was lost in edit, changing the intended meaning. I did not want to write it like it's the only needed rounding mode. Apologies.

Contributor

cznic commented Apr 25, 2017

I am aware of the various different rounding modes - and if you disagree with what I consider intuitive, that's fair.

FTR, in my post the crucial 'I' before 'need' was lost in edit, changing the intended meaning. I did not want to write it like it's the only needed rounding mode. Apologies.

@dongweigogo

This comment has been minimized.

Show comment
Hide comment

dongweigogo commented Apr 27, 2017

similar work in rust

@ianlancetaylor

This comment has been minimized.

Show comment
Hide comment
@ianlancetaylor

ianlancetaylor Apr 27, 2017

Contributor

@dongweigogo From a quick look at the Rust work, that is equivalent to the existing Go functions math.Float64bits and math.Float64frombits. It's not related to the subject of this issue which is, essentially, math.Round.

I don't have any strong opinions on this issue. I note that, as mentioned above, C99 defines double round(double) which returns the nearest integer value of its argument, rounding halfway cases away from zero. It also defines long lround(double) which does the same only it returns an integer type rather than a floating point type. The existence of these functions in C99 is a good argument in favor of including them in Go's math package.

C99 also defines a current rounding mode, set by fesetround, and functions double nearbyint(double), double rint(double) and long lrint(double) that round to the nearest integer using the current rounding mode (the difference between nearbyint and rint is that the latter is permitted to raise the floating-point inexact exception). Implementations are not, however, required to support any particular rounding mode.

Contributor

ianlancetaylor commented Apr 27, 2017

@dongweigogo From a quick look at the Rust work, that is equivalent to the existing Go functions math.Float64bits and math.Float64frombits. It's not related to the subject of this issue which is, essentially, math.Round.

I don't have any strong opinions on this issue. I note that, as mentioned above, C99 defines double round(double) which returns the nearest integer value of its argument, rounding halfway cases away from zero. It also defines long lround(double) which does the same only it returns an integer type rather than a floating point type. The existence of these functions in C99 is a good argument in favor of including them in Go's math package.

C99 also defines a current rounding mode, set by fesetround, and functions double nearbyint(double), double rint(double) and long lrint(double) that round to the nearest integer using the current rounding mode (the difference between nearbyint and rint is that the latter is permitted to raise the floating-point inexact exception). Implementations are not, however, required to support any particular rounding mode.

@mpx

This comment has been minimized.

Show comment
Hide comment
@mpx

mpx Apr 28, 2017

Contributor

I think it's worth adding to math since creating the commonly desired rounding function "round half away from zero" (round(3)) appears obvious, but many straightforward implementations are likely to be subtly incorrect. Eg:

  1. Not handling negative numbers and rounding in the "wrong" direction
  2. When x = 0.5-ULP, Trunc(x+0.5) will incorrectly round to 1 (and similarly for negative numbers)
  3. Not handling NaN correctly
  4. When is x>=2^52, Trunc(x+0.5) may round to even before Trunc, effectively adding 1 [added 2017/06/07]
  5. When -0.5 < x < 0, x may incorrectly round to 0 (instead of -0). [added 2017/09/02]

Hence the suggestion above using Trunc(f+0.5) for simple rounding fails due to (2), (4). https://play.golang.org/p/LNWIKWYlWe

I use the following as a "straightforward" implementation of round(3) in my code:

func Round(n float64) float64 {
    if n >= 0.5 {
        return math.Trunc(n + 0.5)
    }
    if n <= -0.5 {
        return math.Trunc(n - 0.5)
    }
    if math.IsNaN(n) {
        return math.NaN()
    }
    return 0
}

..but it's non-obvious enough that I wouldn't be surprised to find out this function is wrong too :).
[2017/06/07, 2017/09/02] ..it is wrong due to (4), (5). CL proposed below is correct.

A round(3) equivalent in math should handle most uses of floating point rounding and prevent a lot of bugs. Maybe it is reasonable to leave other specific modes to the person who knows why they need them?

Also, a library implementation should be much more efficient using bit manipulation (but with an even less obvious implementation).

Contributor

mpx commented Apr 28, 2017

I think it's worth adding to math since creating the commonly desired rounding function "round half away from zero" (round(3)) appears obvious, but many straightforward implementations are likely to be subtly incorrect. Eg:

  1. Not handling negative numbers and rounding in the "wrong" direction
  2. When x = 0.5-ULP, Trunc(x+0.5) will incorrectly round to 1 (and similarly for negative numbers)
  3. Not handling NaN correctly
  4. When is x>=2^52, Trunc(x+0.5) may round to even before Trunc, effectively adding 1 [added 2017/06/07]
  5. When -0.5 < x < 0, x may incorrectly round to 0 (instead of -0). [added 2017/09/02]

Hence the suggestion above using Trunc(f+0.5) for simple rounding fails due to (2), (4). https://play.golang.org/p/LNWIKWYlWe

I use the following as a "straightforward" implementation of round(3) in my code:

func Round(n float64) float64 {
    if n >= 0.5 {
        return math.Trunc(n + 0.5)
    }
    if n <= -0.5 {
        return math.Trunc(n - 0.5)
    }
    if math.IsNaN(n) {
        return math.NaN()
    }
    return 0
}

..but it's non-obvious enough that I wouldn't be surprised to find out this function is wrong too :).
[2017/06/07, 2017/09/02] ..it is wrong due to (4), (5). CL proposed below is correct.

A round(3) equivalent in math should handle most uses of floating point rounding and prevent a lot of bugs. Maybe it is reasonable to leave other specific modes to the person who knows why they need them?

Also, a library implementation should be much more efficient using bit manipulation (but with an even less obvious implementation).

@Azareal

This comment has been minimized.

Show comment
Hide comment
@Azareal

Azareal May 5, 2017

I need one which rounds 0.17 to 0.2, 0.172 to 0.2, and so on.
float64 rounding would need all sorts of varying precisions to be useful.

And if there's one for float64, then I think there should be one for float32 too.
And sometimes, you just want to truncate a float, not round it.
I have a control panel in one project where a load of information is presented to the end-user, but I don't want to annoy them with like 10 digits for every little thing.

Azareal commented May 5, 2017

I need one which rounds 0.17 to 0.2, 0.172 to 0.2, and so on.
float64 rounding would need all sorts of varying precisions to be useful.

And if there's one for float64, then I think there should be one for float32 too.
And sometimes, you just want to truncate a float, not round it.
I have a control panel in one project where a load of information is presented to the end-user, but I don't want to annoy them with like 10 digits for every little thing.

@btracey

This comment has been minimized.

Show comment
Hide comment
@mjibson

This comment has been minimized.

Show comment
Hide comment
@mjibson

mjibson May 10, 2017

Contributor

@btracey That function is also broken. See https://github.com/gonum/floats/blob/a2cbc5c70616cd18491ef2843231f6ce28b2cb02/floats.go#L605 where it returns if x*10^n > MaxFloat64, and returns the original x unchanged with no indication of error. This is more edge cases not correctly covered, due to a limitation in the implementation.

CockroachDB today realized that our round(float, n) implementation with RoundHalfEven rounding was wrong. Two of us spent half the day trying to figure out a correct implementation that didn't have edge cases. Our solution was to convert to an arbitrary-precision decimal, have it do the rounding (which is very well tested), then convert back to a float. This isn't fast, but at least it's correct. It is unfortunate that we couldn't figure out how to do this using just floats. (cockroachdb/cockroach#15847)

It is unfortunate that Go programmers are spending so much time on this problem, and at best we can only produce broken implementations using existing float methods. Having a high quality rounding implementation would alleviate lots of duplicate and incorrect work.

Contributor

mjibson commented May 10, 2017

@btracey That function is also broken. See https://github.com/gonum/floats/blob/a2cbc5c70616cd18491ef2843231f6ce28b2cb02/floats.go#L605 where it returns if x*10^n > MaxFloat64, and returns the original x unchanged with no indication of error. This is more edge cases not correctly covered, due to a limitation in the implementation.

CockroachDB today realized that our round(float, n) implementation with RoundHalfEven rounding was wrong. Two of us spent half the day trying to figure out a correct implementation that didn't have edge cases. Our solution was to convert to an arbitrary-precision decimal, have it do the rounding (which is very well tested), then convert back to a float. This isn't fast, but at least it's correct. It is unfortunate that we couldn't figure out how to do this using just floats. (cockroachdb/cockroach#15847)

It is unfortunate that Go programmers are spending so much time on this problem, and at best we can only produce broken implementations using existing float methods. Having a high quality rounding implementation would alleviate lots of duplicate and incorrect work.

@btracey

This comment has been minimized.

Show comment
Hide comment
@btracey

btracey May 10, 2017

Contributor

Thanks for the report. Would you mind opening an issue?

Contributor

btracey commented May 10, 2017

Thanks for the report. Would you mind opening an issue?

@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc May 15, 2017

Contributor

It's certainly true that we don't want hidden state rounding modes. The C99 round family, as @ianlancetaylor points out, has a fixed rounding mode regardless of hidden mode. The only difference between round (returns float) and lround (returns long) is that the latter sets errno when it can't represent the result. We can probably let users check that and have plain

float64 Round(float64 f) // round to integer, halfway away from 0, like C round

If users need to convert to int, then instead of having an lround equivalent, they can use int(math.Round(f)) or int64(math.Round(f)) or whatever type is desired.

Accepting based on discussion with @golang/proposal-review.

Contributor

rsc commented May 15, 2017

It's certainly true that we don't want hidden state rounding modes. The C99 round family, as @ianlancetaylor points out, has a fixed rounding mode regardless of hidden mode. The only difference between round (returns float) and lround (returns long) is that the latter sets errno when it can't represent the result. We can probably let users check that and have plain

float64 Round(float64 f) // round to integer, halfway away from 0, like C round

If users need to convert to int, then instead of having an lround equivalent, they can use int(math.Round(f)) or int64(math.Round(f)) or whatever type is desired.

Accepting based on discussion with @golang/proposal-review.

@rsc rsc changed the title from proposal: math: reconsider the lack of a standard library rounding function for float64 to math: add Round May 15, 2017

@rsc rsc modified the milestones: Go1.10, Proposal May 15, 2017

@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc May 15, 2017

Contributor

For next round.

Contributor

rsc commented May 15, 2017

For next round.

@AlekSi

This comment has been minimized.

Show comment
Hide comment
@AlekSi

AlekSi May 17, 2017

Contributor

Accepting based on discussion with @golang/proposal-review.

Sorry for offtopic, but can you make this team visible somehow? For me, this link returns 404.

Contributor

AlekSi commented May 17, 2017

Accepting based on discussion with @golang/proposal-review.

Sorry for offtopic, but can you make this team visible somehow? For me, this link returns 404.

@bradfitz

This comment has been minimized.

Show comment
Hide comment
@bradfitz
Member

bradfitz commented May 17, 2017

@AlekSi

This comment has been minimized.

Show comment
Hide comment
@AlekSi

AlekSi May 17, 2017

Contributor

Making this team visible (https://github.com/orgs/golang/teams/proposal-review/edit) should fix 404 for other people, so you don't need to write this list down to README, Wiki, etc.

(Again, really sorry for derailing. If you don't totally agree with making this team visible, I will probably post to maillist to discuss it.)

Contributor

AlekSi commented May 17, 2017

Making this team visible (https://github.com/orgs/golang/teams/proposal-review/edit) should fix 404 for other people, so you don't need to write this list down to README, Wiki, etc.

(Again, really sorry for derailing. If you don't totally agree with making this team visible, I will probably post to maillist to discuss it.)

@cespare

This comment has been minimized.

Show comment
Hide comment
@cespare

cespare May 17, 2017

Contributor

I'd like to take this. Feel free to unassign me if you object.

Contributor

cespare commented May 17, 2017

I'd like to take this. Feel free to unassign me if you object.

@cespare cespare self-assigned this May 17, 2017

@btracey

This comment has been minimized.

Show comment
Hide comment
@btracey

btracey May 17, 2017

Contributor

Just to ask: Should the signature allow rounding to non-integers? For instance Round(v float64, prec int). This would enable @Azareal 's feature suggestion of being able to round 0.17234 to 0.172. I've used this behavior a few times, and implementing the full functionality would address the concerns of @mjibson about outside groups implementing the "precision" version with bugs.

Contributor

btracey commented May 17, 2017

Just to ask: Should the signature allow rounding to non-integers? For instance Round(v float64, prec int). This would enable @Azareal 's feature suggestion of being able to round 0.17234 to 0.172. I've used this behavior a few times, and implementing the full functionality would address the concerns of @mjibson about outside groups implementing the "precision" version with bugs.

@griesemer

This comment has been minimized.

Show comment
Hide comment
@griesemer

griesemer May 17, 2017

Contributor

@btracey No. See also @rsc 's comment.

If you want to round to 3 digits after the comma, why can't you simply do Round(x * 1e3)/1e3?

Contributor

griesemer commented May 17, 2017

@btracey No. See also @rsc 's comment.

If you want to round to 3 digits after the comma, why can't you simply do Round(x * 1e3)/1e3?

@btracey

This comment has been minimized.

Show comment
Hide comment
@btracey

btracey May 17, 2017

Contributor

Because of overflow (which is the error in Gonum's implementation as well).

Contributor

btracey commented May 17, 2017

Because of overflow (which is the error in Gonum's implementation as well).

@griesemer

This comment has been minimized.

Show comment
Hide comment
@griesemer

griesemer May 17, 2017

Contributor

@btracey I assume you mean overflow of x * 1e3 in this case? How likely is this given the huge exponent ranges of floats?

Contributor

griesemer commented May 17, 2017

@btracey I assume you mean overflow of x * 1e3 in this case? How likely is this given the huge exponent ranges of floats?

@btracey

This comment has been minimized.

Show comment
Hide comment
@btracey

btracey May 17, 2017

Contributor

I personally haven't come across the problem, but it sounds like @mjibson may have.

Contributor

btracey commented May 17, 2017

I personally haven't come across the problem, but it sounds like @mjibson may have.

@griesemer

This comment has been minimized.

Show comment
Hide comment
@griesemer

griesemer May 17, 2017

Contributor

I see.

Having a simple Round as proposed doesn't have this problem, of course. But if there's a chance that overflow can occur, then the number is so huge that rounding is pretty meaningless (the mantissa is not precise enough in the first place). Or I don't really understand the problem.

Contributor

griesemer commented May 17, 2017

I see.

Having a simple Round as proposed doesn't have this problem, of course. But if there's a chance that overflow can occur, then the number is so huge that rounding is pretty meaningless (the mantissa is not precise enough in the first place). Or I don't really understand the problem.

@mjibson

This comment has been minimized.

Show comment
Hide comment
@mjibson

mjibson May 17, 2017

Contributor

I care about the precision argument because it's part of an API I need to provide. I think that's an ok thing to not provide here as I have some special requirements, like round half even, which make more sense to implement on top of this round API.

Contributor

mjibson commented May 17, 2017

I care about the precision argument because it's part of an API I need to provide. I think that's an ok thing to not provide here as I have some special requirements, like round half even, which make more sense to implement on top of this round API.

@gopherbot

This comment has been minimized.

Show comment
Hide comment
@gopherbot

gopherbot commented May 18, 2017

CL https://golang.org/cl/43652 mentions this issue.

@mpx

This comment has been minimized.

Show comment
Hide comment
@mpx

mpx May 18, 2017

Contributor

@cespare I wrote and tested an implementation the other day (now linked above), I hope you don't mind.

Contributor

mpx commented May 18, 2017

@cespare I wrote and tested an implementation the other day (now linked above), I hope you don't mind.

@rsc

This comment has been minimized.

Show comment
Hide comment
@rsc

rsc May 18, 2017

Contributor

[off topic] @AlekSi, golang/proposal-review team is already "visible" but apparently (surprise to me) that does not mean publicly visible. I thought it was public; I don't know how to make it more public. But I confirm that it doesn't work when not logged in. The description says "A visible team can be seen and @mentioned by every member of this organization." I guess that means "not public". Ironically part of the reason I created that team list was to have a public list. Oh well, live and learn, and my apologies.

Contributor

rsc commented May 18, 2017

[off topic] @AlekSi, golang/proposal-review team is already "visible" but apparently (surprise to me) that does not mean publicly visible. I thought it was public; I don't know how to make it more public. But I confirm that it doesn't work when not logged in. The description says "A visible team can be seen and @mentioned by every member of this organization." I guess that means "not public". Ironically part of the reason I created that team list was to have a public list. Oh well, live and learn, and my apologies.

@cespare cespare removed their assignment May 18, 2017

@cespare

This comment has been minimized.

Show comment
Hide comment
@cespare

cespare May 18, 2017

Contributor

@mpx thanks!

Contributor

cespare commented May 18, 2017

@mpx thanks!

@DanieleDaccurso

This comment has been minimized.

Show comment
Hide comment
@DanieleDaccurso

DanieleDaccurso May 21, 2017

Maybe not only having Round but also short-hand functions to Ceil / round-up and Floor / round-off would be nice.

DanieleDaccurso commented May 21, 2017

Maybe not only having Round but also short-hand functions to Ceil / round-up and Floor / round-off would be nice.

@hikari-no-yume

This comment has been minimized.

Show comment
Hide comment
@hikari-no-yume

hikari-no-yume Jul 9, 2017

Might I point out that both x86/x64 and ARM can do IEEE 754-compliant rounding in a single instruction? It would seem wasteful not to make use of that where available.

hikari-no-yume commented Jul 9, 2017

Might I point out that both x86/x64 and ARM can do IEEE 754-compliant rounding in a single instruction? It would seem wasteful not to make use of that where available.

@ianlancetaylor

This comment has been minimized.

Show comment
Hide comment
@ianlancetaylor

ianlancetaylor Jul 9, 2017

Contributor

@hikari-no-yume Once we get the first CL, with tests, in for 1.10, please go ahead and send processor-specific optimizations as appropriate. Thanks.

Contributor

ianlancetaylor commented Jul 9, 2017

@hikari-no-yume Once we get the first CL, with tests, in for 1.10, please go ahead and send processor-specific optimizations as appropriate. Thanks.

@dansouza

This comment has been minimized.

Show comment
Hide comment
@dansouza

dansouza Jul 10, 2017

@hikari-no-yume came here to say this. I think we should just use the native instructions for float rounding by default on the default math.Round function (behaving as one would expect rounding to behave in their platform) and let the user decide the rounding mode and other peculiarities either by having different functions for each mode or passing an argument.

dansouza commented Jul 10, 2017

@hikari-no-yume came here to say this. I think we should just use the native instructions for float rounding by default on the default math.Round function (behaving as one would expect rounding to behave in their platform) and let the user decide the rounding mode and other peculiarities either by having different functions for each mode or passing an argument.

@mpx

This comment has been minimized.

Show comment
Hide comment
@mpx

mpx Jul 13, 2017

Contributor

The implemention I've linked above is simple enough to be inlined by the compiler which makes it reasonably fast. Due to function call overhead, I suspect the native instructions may need to be an instrinsic to realise any significant benefit (but I haven't tested it).

Contributor

mpx commented Jul 13, 2017

The implemention I've linked above is simple enough to be inlined by the compiler which makes it reasonably fast. Due to function call overhead, I suspect the native instructions may need to be an instrinsic to realise any significant benefit (but I haven't tested it).

@golang golang deleted a comment from minicase Jul 20, 2017

@a-h

This comment has been minimized.

Show comment
Hide comment
@a-h

a-h Sep 1, 2017

Contributor

I think it would be best to have a math/round package and call the Round function AwayFromZero in order to leave space for ToZero, ToEven, ToPositiveInfinity and ToNegativeInfinity variants.

Given that different programming languages have different implementations, having the rounding algorithm in the name usefully clarifies the exact implementation to the reader.

I also think it's important to be able to round to an arbitrary number of decimal places.

In my case, I needed this functionality when doing an online course where the tests needed to match an existing Python implementation exactly, so I wrote some rounding functions that did that and follows the naming pattern I outlined, but it doesn't handle some edge cases like infinity, NaN and overflow like a proper library implementation would.

Contributor

a-h commented Sep 1, 2017

I think it would be best to have a math/round package and call the Round function AwayFromZero in order to leave space for ToZero, ToEven, ToPositiveInfinity and ToNegativeInfinity variants.

Given that different programming languages have different implementations, having the rounding algorithm in the name usefully clarifies the exact implementation to the reader.

I also think it's important to be able to round to an arbitrary number of decimal places.

In my case, I needed this functionality when doing an online course where the tests needed to match an existing Python implementation exactly, so I wrote some rounding functions that did that and follows the naming pattern I outlined, but it doesn't handle some edge cases like infinity, NaN and overflow like a proper library implementation would.

@mpx

This comment has been minimized.

Show comment
Hide comment
@mpx

mpx Sep 1, 2017

Contributor

Most of those rounding options already exist:

  • math.Floor (toward -Inf)
  • math.Ceil (toward +Inf)
  • math.Trunc (toward 0)

It's usually a mistake to round floating point to n decimal places where n > 0 since it may introduce an error (fractional base10 numbers can't be represented in base2). Depending on use case, it is usually better to either:

  1. Round on output/display (fmt.Sprintf), or
  2. Use a decimal library to perform the calculations in base 10.
Contributor

mpx commented Sep 1, 2017

Most of those rounding options already exist:

  • math.Floor (toward -Inf)
  • math.Ceil (toward +Inf)
  • math.Trunc (toward 0)

It's usually a mistake to round floating point to n decimal places where n > 0 since it may introduce an error (fractional base10 numbers can't be represented in base2). Depending on use case, it is usually better to either:

  1. Round on output/display (fmt.Sprintf), or
  2. Use a decimal library to perform the calculations in base 10.
@a-h

This comment has been minimized.

Show comment
Hide comment
@a-h

a-h Sep 1, 2017

Contributor

I think you're right. I'm really only rounding to display and match other languages, so maybe I shouldn't care about having a rounding function which supports rounding to arbitrary digits.

I just expected it to be there based on other languages I use regularly like Python (https://docs.python.org/3/library/functions.html#round) and C# (https://msdn.microsoft.com/en-us/library/75ks3aby.aspx).

Contributor

a-h commented Sep 1, 2017

I think you're right. I'm really only rounding to display and match other languages, so maybe I shouldn't care about having a rounding function which supports rounding to arbitrary digits.

I just expected it to be there based on other languages I use regularly like Python (https://docs.python.org/3/library/functions.html#round) and C# (https://msdn.microsoft.com/en-us/library/75ks3aby.aspx).

@gdm85

This comment has been minimized.

Show comment
Hide comment
@gdm85

gdm85 Nov 22, 2017

I made a gist for Round() for those who need it before February 2018 (planned release of Go 1.10)

gdm85 commented Nov 22, 2017

I made a gist for Round() for those who need it before February 2018 (planned release of Go 1.10)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment