2016-09-17 7 views
11

골란에서 가장 가까운 0.05로 반올림하는 함수를 찾고 있습니다. 함수 사용의 최종 결과는 항상 0.05의 인수 여야합니다. 골란 가장 가까운 값으로 반올림 0.05

Round(0.363636) // 0.35 
Round(3.232) // 3.25 
Round(0.4888) // 0.5 

(라운드 아직 존재하지 않는 기능, 나는이 대답에 포함될 수 바라고) : 여기


내가 찾고 있어요 함수에 대한 출력의 몇 가지 예입니다 나는 나이를 수색하여 답을 찾지 못했습니다.

+0

온라인으로 하나를 찾았지만 질문에 답을 얻지 못했습니다./ – Acidic

+0

Related : [Go : 승수로 정수로 float64 변환하기] (http://stackoverflow.com/questions/33206059/) go-converting-float64-int-with-multiplier) – icza

+0

올바른 결과를 제공하는 반올림 함수가있는 경우이를 잘라내어 결과의 정밀도를 관리하면됩니다. 일종의 ham-fisted 접근 방식은 https://play.golang.org/p/DRTTkQQI42 일 것이다. (가장자리 테스트는 안됨) – abhink

답변

50

Go 1.10이 출시되었으며 math.Round() 기능이 추가되었습니다. 이 기능은 (기본적으로 운전가 "가장 가까운 1.0 라운드"입니다) 가장 가까운 정수로 반올림, 우리는 아주 쉽게 우리의 선택의 단위로 반올림 함수 구성 할 수있는 사용 :

func Round(x, unit float64) float64 { 
    return math.Round(x/unit) * unit 
} 

테스트를 그것 :

fmt.Println(Round(0.363636, 0.05)) // 0.35 
fmt.Println(Round(3.232, 0.05)) // 3.25 
fmt.Println(Round(0.4888, 0.05)) // 0.5 

fmt.Println(Round(-0.363636, 0.05)) // -0.35 
fmt.Println(Round(-3.232, 0.05)) // -3.25 
fmt.Println(Round(-0.4888, 0.05)) // -0.5 

Go Playground에서 시도해보십시오.

원래 대답은 math.Round()이없는 시대에 만들어졌으며 사용자 지정 Round() 기능의 논리를 자세히 설명합니다. 그것은 교육적인 목적을위한 것입니다.


이전 Go1.10 시대에는 math.Round()이 없었습니다. 하지만 ...

반올림 작업을 쉽게 float64 =>int64 converison에 의해 구현 될 수 있지만,주의가 반올림하지만 정수 부분을 (Go: Converting float64 to int with multiplier에서 자세한 내용을 참조) 유지되지 변환을 int로 플로트로주의해야합니다. 예를 들어

:

var f float64 
f = 12.3 
fmt.Println(int64(f)) // 12 
f = 12.6 
fmt.Println(int64(f)) // 12 

결과 두 경우 12, 정수 부분이다. 반올림 '기능'을 얻으려면 0.5을 추가하십시오.

지금까지는 그렇게 좋았습니다. 그러나 우리는 정수로 반올림하고 싶지 않습니다. 우리는 1 개 분수 자리에 모아 원했다면, 우리는 0.5를 추가하고 변환하기 전에 10을 곱합니다 :

f = 12.31 
fmt.Println(float64(int64(f*10+0.5))/10) // 12.3 
f = 12.66 
fmt.Println(float64(int64(f*10+0.5))/10) // 12.7 

을 그래서 기본적으로 당신은 당신이 라운드 할 장치의 역수로 곱하면됩니다.1/0.05 = 20에 의해 곱셈, 0.05 단위로 반올림하려면

f = 12.31 
fmt.Println(float64(int64(f*20+0.5))/20) // 12.3 
f = 12.66 
fmt.Println(float64(int64(f*20+0.5))/20) // 12.65 

함수로이 포장 :

func Round(x, unit float64) float64 { 
    return float64(int64(x/unit+0.5)) * unit 
} 

그것을 사용 :

fmt.Println(Round(0.363636, 0.05)) // 0.35 
fmt.Println(Round(3.232, 0.05)) // 3.25 
fmt.Println(Round(0.4888, 0.05)) // 0.5 

Go Playground의 예를보십시오.

unit=0.05으로 반올림하면 3.25이 아니라 0.35000000000000003으로 정확하게 인쇄됩니다. float64 숫자는 IEEE-754 표준이라는 유한 정밀도를 사용하여 저장되기 때문입니다. 자세한 내용은 Golang converting float64 to int error을 참조하십시오.

또한 unit은 "모든"숫자 일 수 있습니다. 1 인 경우 Round()은 기본적으로 가장 가까운 정수로 반올림됩니다. 10 인 경우 십진수로 반올림되며 0.01 인 경우 2 소수 자릿수로 반올림됩니다.

또한 음수로 Round()를 호출 할 때, 당신은 놀라운 결과를 얻을 수 있습니다 :

fmt.Println(Round(-0.363636, 0.05)) // -0.3 
fmt.Println(Round(-3.232, 0.05)) // -3.2 
fmt.Println(Round(-0.4888, 0.05)) // -0.45 

이 -as가하는 이전에 변환 정수 부분을 유지, 그리고 예를 들어, 정수 부분에 대해 상기 있기 때문이다 -1.6은 보다 크고 1.6의 정수 부분은 1.6보다 작은 1 인 반면 -1입니다.

당신이 -0.35 대신 -0.30가 될 -0.363636을 원한다면, 음수의 경우에는 Round() 함수 내에서 -0.5 대신 0.5 추가 할 수 있습니다.

func Round2(x, unit float64) float64 { 
    if x > 0 { 
     return float64(int64(x/unit+0.5)) * unit 
    } 
    return float64(int64(x/unit-0.5)) * unit 
} 

그리고 그것을 사용 : 우리의 개선 Round2() 함수를 참조

fmt.Println(Round2(-0.363636, 0.05)) // -0.35 
fmt.Println(Round2(-3.232, 0.05)) // -3.25 
fmt.Println(Round2(-0.4888, 0.05)) // -0.5 

편집 :

당신의 코멘트를 해결하기 위해 : 당신은 비 "처럼"하지 않기 때문에 -exact 0.35000000000000003, 형식을 지정하고 다시 구문 분석을 제안했습니다.

formatted, err := strconv.ParseFloat(fmt.Sprintf("%.2f", rounded), 64) 

그리고이 "겉보기"결과는 정확히 인쇄 결과로 0.35이됩니다.

그러나 이것은 단지 "환상"입니다. 0.35은 IEEE-754 표준을 사용하여 유한 비트로 표시 할 수 없으므로 숫자로 어떤 작업을하든 관계없이 float64 유형의 값으로 저장하면 정확히 0.35 (IEEE-754 번호 매우 가까이에있다). fmt.Println()은 이미 에 약간의 반올림을하기 때문에 0.35으로 표시됩니다.(심지어 이보다 수 있습니다) 그렇지 좋네요 :

fmt.Printf("%.30f\n", Round(0.363636, 0.05)) 
fmt.Printf("%.30f\n", Round(3.232, 0.05)) 
fmt.Printf("%.30f\n", Round(0.4888, 0.05)) 

출력은 : 당신이 더 높은 정밀도로 인쇄하려고하면

그러나 Go Playground에 그것을 시도 :

0.349999999999999977795539507497 
3.250000000000000000000000000000 
0.500000000000000000000000000000 

참고가에 다른 하나는 3.250.5이 정확하기 때문에 이진수로 표현하기 때문에 정확하게 유한 비트로 나타낼 수 있습니다.

3.25 = 3 + 0.25 = 11.01binary 
0.5 = 0.1binary 

수업이란 무엇입니까? 결과를 서식 지정하고 다시 구문 분석 할 필요가 없습니다. 정확한 값이 아니기 때문에 (인쇄시 기본 fmt.Println() 서식 규칙에 따라 float64 값이 다를 수 있습니다). 당신이 좋은 인쇄 형식을 원하는 경우처럼 정밀하게 포맷 :

func main() { 
    fmt.Printf("%.3f\n", Round(0.363636, 0.05)) 
    fmt.Printf("%.3f\n", Round(3.232, 0.05)) 
    fmt.Printf("%.3f\n", Round(0.4888, 0.05)) 
} 

func Round(x, unit float64) float64 { 
    return float64(int64(x/unit+0.5)) * unit 
} 

그리고합니다 (Go Playground에 그것을 시도) 정확합니다

0.350 
3.250 
0.500 

을하거나 100 곱해 및 작업 정수형이므로 표현이나 반올림 오류가 발생할 수 없습니다.

+5

순수한 천재 이상의 것은 없습니다. 고맙습니다. icza. – Acidic

+0

@Acidic 음수에 적용하는 것에 대해서는 편집을 참조하십시오. – icza

+0

네, 고맙습니다. 관심있는 모든 사람들을 위해 https://play.golang.org/p/jxILFBYBEF에서 사용할 수있는 0.363636 = 0.35000000000000003의 문제를 해결하기 위해 함수를 편집했습니다. – Acidic

관련 문제