IT

부동값을 C의 소수점 이후 두 자리까지만 제한하려면 어떻게 해야 합니까?

itgroup 2022. 11. 7. 21:28
반응형

부동값을 C의 소수점 이후 두 자리까지만 제한하려면 어떻게 해야 합니까?

플로트 값(37.7779)을 C의 소수점 2자리(37.78)로 반올림하려면 어떻게 해야 합니까?

를 반올림하는 는, 「」를 해 주세요."%.2f"형식 문자열이 정답입니다.수행할 수 있습니다.

#include <math.h>

float val = 37.777779;

float rounded_down = floorf(val * 100) / 100;   /* Result: 37.77 */
float nearest = roundf(val * 100) / 100;  /* Result: 37.78 */
float rounded_up = ceilf(val * 100) / 100;      /* Result: 37.78 */

선택할 수 있는 반올림 규칙에는 반올림(소수점 두 자리 이후 잘라내기), 반올림 및 반올림 세 가지가 있습니다.보통은 가장 가까운 곳으로 동그랗게 오릅니다.

몇몇 다른 사람들이 지적했듯이 부동소수점 표현의 기이한 점 때문에 반올림된 이러한 값은 정확히 "명확한" 소수점 값은 아닐 수 있지만 매우 근접합니다.

반올림에 대한 자세한 정보, 특히 가장 가까운 반올림에 대한 동점 처리 규칙에 대한 자세한 내용은 반올림 관련 위키피디아 문서를 참조하십시오.

printf에서 %.2f를 사용합니다.소수점 2개만 출력됩니다.

예를 들어:

printf("%.2f", 37.777779);

출력:

37.77

「」를 해 주세요.printf능능패패 패다다다다다플로트로서 가치를 얻고 싶어도, 이 기능을 사용하는 것이 가장 좋습니다.snprintfatof:

#include <math.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>

double dround(double val, int dp) {
    int charsNeeded = 1 + snprintf(NULL, 0, "%.*f", dp, val);
    char *buffer = malloc(charsNeeded);
    snprintf(buffer, charsNeeded, "%.*f", dp, val);
    double result = atof(buffer);
    free(buffer);
    return result;
}

제가 이렇게 말하는 이유는 현재 가장 많이 투표된 답변과 다른 답변에서 보여지는 접근법(100을 곱하고, 가장 가까운 정수로 반올림하고, 다시 100으로 나누는 방법)에 두 가지 면에서 결함이 있기 때문입니다.

  • 일부 값에서는 부동 소수점 숫자의 부정확성으로 인해 100을 곱하면 반올림 방향을 결정하는 소수 자릿수가 4에서 5로 변경되거나 그 반대로 변경되기 때문에 잘못된 방향으로 반올림됩니다.
  • 일부 값에서는 곱한 후 100으로 나누면 라운드 트립이 되지 않습니다. 즉, 반올림이 이루어지지 않더라도 최종 결과가 잘못됩니다.

첫 번째 오류(반올림 방향이 잘못될 수 있음)를 설명하려면 이 프로그램을 실행하십시오.

int main(void) {
    // This number is EXACTLY representable as a double
    double x = 0.01499999999999999944488848768742172978818416595458984375;

    printf("x: %.50f\n", x);

    double res1 = dround(x, 2);
    double res2 = round(100 * x) / 100;

    printf("Rounded with snprintf: %.50f\n", res1);
    printf("Rounded with round, then divided: %.50f\n", res2);
}

다음의 출력이 표시됩니다.

x: 0.01499999999999999944488848768742172978818416595459
Rounded with snprintf: 0.01000000000000000020816681711721685132943093776703
Rounded with round, then divided: 0.02000000000000000041633363423443370265886187553406

여기서 시작한 값은 0.015보다 작기 때문에 소수점 2자리로 반올림했을 때의 수학 정답은 0.01입니다.물론 0.01이 배수로 정확하게 표현되는 것은 아니지만, 0.01에 가장 가까운 배수가 될 것으로 예상됩니다.사용.snprintf 수 , '이러다'를 round(100 * x) / 100요? 0.02예요? ★★★★★★★★★★★★★★★★★★100 * x1.5로 하다따라서 100을 곱하면 올바른 반올림 방향이 변경됩니다.

번째 유형의 오류를 설명하기 위해 다음과 같은 이유로 인해 결과가 잘못될 수 있습니다.* 100 ★★★★★★★★★★★★★★★★★」/ 100실제로 서로를 역행하는 것이 아니라 매우 큰 수로 비슷한 운동을 할 수 있다.

int main(void) {
    double x = 8631192423766613.0;

    printf("x: %.1f\n", x);

    double res1 = dround(x, 2);
    double res2 = round(100 * x) / 100;

    printf("Rounded with snprintf: %.1f\n", res1);
    printf("Rounded with round, then divided: %.1f\n", res2);
}

는 이제, '정수값'으로 되어 있어요.double반올림 후 결과는 처음과 같은 숫자여야 하는 거 맞죠?

위의 프로그램을 실행하면 다음과 같이 표시됩니다.

x: 8631192423766613.0
Rounded with snprintf: 8631192423766613.0
Rounded with round, then divided: 8631192423766612.0

우리 아, 아, 아.snprintf다시 실패합니다.methodmultiply-the-round-then-the-then-then-then-then-then-then-divide의 수학적으로 올바른 을 반환하기 8631192423766613.0 * 100,863119242376661300.0 수 것은 가까운 값은 「」, 「2」, 「2」입니다.가장 가까운 값은863119242376661248.0이 됩니다8631192423766612.0 - 번호입니다.

정도면 충분히 할 수 있을 입니다.roundf반올림을 할 수 .snprintf대신.만약 그것이 당신에게 끔찍한 해킹으로 느껴진다면, 아마도 당신은 그것이 기본적으로 CPython이 하는 이라는 것을 알면 안심할 수 있을 것이다.

C++(또는 C-스타일 캐스팅이 있는 C)에서 다음 함수를 만들 수 있습니다.

/* Function to control # of decimal places to be output for x */
double showDecimals(const double& x, const int& numDecimals) {
    int y=x;
    double z=x-y;
    double m=pow(10,numDecimals);
    double q=z*m;
    double r=round(q);

    return static_cast<double>(y)+(1.0/m)*r;
}

★★★★★★★★★★★★★★★.std::cout << showDecimals(37.777779,2);37.78을 생성합니다.

물론 이 함수에 5가지 변수를 모두 만들 필요는 없지만 논리를 볼 수 있도록 그대로 둡니다.간단한 해결 방법이 있을 수 있지만, 특히 필요에 따라 소수점 이후의 자리수를 조정할 수 있기 때문에 이 방법은 효과적입니다.

Andrew ColesonAraK의 답변은 인쇄의 가치를 반올림한다고 가정하면 다음과 같습니다.

printf("%.2f", 37.777779);

단, 내부 사용(예를 들어 다른 값과 비교)을 위해 정확히 37.78로 반올림하려는 경우에는 부동소수점 숫자가 작동하는 방식으로 인해 이는 좋은 생각이 아닙니다. 일반적으로 부동소수점 값을 동등하게 비교하는 것은 원치 않습니다. 대신 목표값 +/- 시그마 값을 사용하십시오.또는 숫자를 알려진 정밀도의 문자열로 인코딩하여 비교합니다.

관련 질문에 대한 Greg Hewgill의 답변 링크를 참조하십시오. 이 링크에서는 재무 계산에 부동 소수점을 사용하지 않는 이유도 다룹니다.

또, C++ 를 사용하고 있는 경우는, 다음과 같은 함수를 작성할 수 있습니다.

string prd(const double x, const int decDigits) {
    stringstream ss;
    ss << fixed;
    ss.precision(decDigits); // set # places after decimal
    ss << x;
    return ss.str();
}

임의의 할 수 있습니다.myDoublen다음과 같은 코드를 가진 소수점 뒤의 자리:

std::cout << prd(myDouble,n);

코드 정의:

#define roundz(x,d) ((floor(((x)*pow(10,d))+.5))/pow(10,d))

결과:

a = 8.000000
sqrt(a) = r = 2.828427
roundz(r,2) = 2.830000
roundz(r,3) = 2.828000
roundz(r,5) = 2.828430

다음 항목을 사용할 수 있습니다.

float ceilf(float x); // don't forget #include <math.h> and link with -lm.

예:

float valueToRound = 37.777779;
float roundedValue = ceilf(valueToRound * 100) / 100;

이거 어때:

float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);
printf("%.2f", 37.777779);

C 문자열에 쓰는 경우:

char number[24]; // dummy size, you should take care of the size!
sprintf(number, "%.2f", 37.777779);

먼저 이 질문에 대한 또 다른 답을 덧붙이는 이유를 설명하겠습니다.이상적인 세계에서는 라운딩이 그다지 큰 문제가 되지 않습니다.그러나 실제 시스템에서는 예상과 다른 반올림 결과를 초래할 수 있는 몇 가지 문제에 대처해야 할 수 있습니다.예를 들어 최종 결과가 소수점 2자리 숫자로 반올림되어 사용자에게 표시되는 재무 계산을 수행할 수 있습니다.이러한 값은 소수점 2자리보다 많은 데이터베이스에 고정 정밀하게 저장됩니다(다양한 이유로 최적의 장소 수가 없습니다). 각 시스템의 특정 상황에 따라 달라집니다.스템은 예를 들어 가격이 단위당 1페니의 일부인 작은 항목과 결과가 엡실론 플러스/플러스인 값에 대해 수행된 부동 소수점 계산을 지원해야 한다.나는 수년간 이러한 문제에 직면하여 나 자신의 전략을 발전시켜 왔다.모든 시나리오에 직면했거나 최선의 답변을 가지고 있다고는 할 수 없지만, 이러한 문제를 해결하기 위한 지금까지의 접근방식의 예를 다음에 제시하겠습니다.

소수점 6자리를 다음과 같은 반올림 함수/방법을 사용하여 부동/이중(특정 적용에 대한 임의 결정) 계산에 충분한 정밀도로 간주한다고 가정합니다.

double Round(double x, int p)
{
    if (x != 0.0) {
        return ((floor((fabs(x)*pow(double(10.0),p))+0.5))/pow(double(10.0),p))*(x/fabs(x));
    } else {
        return 0.0;
    }
}

결과 표시를 위해 소수점 이하 2자리 반올림을 다음과 같이 수행할 수 있다.

double val;
// ...perform calculations on val
String(Round(Round(Round(val,8),6),2));

★★★의 val = 6.825 는 입니다.6.83역시나

★★★의 val = 6.824999 는 입니다.6.82 계산 6.824999소수점 7번째 자리는 0입니다.

위해서val = 6.8249999, 결과는 다음과 같습니다.6.83소수점 이하 일곱 번째 자리는9이 경우,Round(val,6)원하는 결과를 제공하는 함수입니다.이 경우, 임의의 수의 후행자가 있을 수 있습니다.9s.

위해서val = 6.824999499999, 결과는 다음과 같습니다.6.83첫 번째 단계로 소수점 이하 8자리 반올림.Round(val,8)는 계산된 부동소수점 결과가 다음과 같이 계산되는 귀찮은 경우를 처리합니다.6.8249995단, 내부적으로는6.824999499999....

마지막으로 질문의 예시는...val = 37.777779을 낳다37.78.

이 접근방식은 다음과 같이 더욱 일반화될 수 있습니다.

double val;
// ...perform calculations on val
String(Round(Round(Round(val,N+2),N),2));

여기서 N은 플로트/더블의 모든 중간 계산에 대해 유지해야 할 정밀도이다.이것은 음의 값에도 작용합니다.나는 이 접근법이 모든 가능성에 대해 수학적으로 정확한지 모르겠다.

a를 반올림할 방법이 없다float타인에게float동그란 것이float는 나타낼 수 없는 경우가 있습니다(부동소수점 숫자의 제한).예를 들어, 37.7779에서 37.78로 반올림한다고 가정합니다. 그러나 가장 가까운 대표 숫자는 37.781입니다.

, '둥근'을 할 수 있습니다.float형식 문자열 기능을 사용하여 지정합니다.

...또는 라이브러리 없이 구식 방식으로 작업을 수행할 수도 있습니다.

float a = 37.777779;

int b = a; // b = 37    
float c = a - b; // c = 0.777779   
c *= 100; // c = 77.777863   
int d = c; // d = 77;    
a = b + d / (float)100; // a = 37.770000;

물론 번호에서 추가 정보를 제거하고 싶다면.

플로트 숫자를 반올림하기 위해 이 매크로를 만들었습니다.헤더 또는 파일에 추가

#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c)))

다음은 예를 제시하겠습니다.

float x = ROUNDF(3.141592, 100)

x = 3.14 :)

사용하다float roundf(float x).

"라운드 함수는 인수를 부동소수점 형식의 가장 가까운 정수값으로 반올림하여 현재 반올림 방향에 관계없이 0에서 반올림합니다." C11dr § 7.12.9.5

#include <math.h>
float y = roundf(x * 100.0f) / 100.0f; 

고객님의 요구에 따라float실장에서는, 반쪽인 것처럼 보이는 숫자는 없습니다.플로팅 포인트는 일반적으로 베이스 2를 지향하고 있기 때문입니다.또한, 가장 가까운 부분까지 정확하게 반올림합니다.0.01모든 "반쪽" 케이스가 가장 어려운 문제입니다.

void r100(const char *s) {
  float x, y;
  sscanf(s, "%f", &x);
  y = round(x*100.0)/100.0;
  printf("%6s %.12e %.12e\n", s, x, y);
}

int main(void) {
  r100("1.115");
  r100("1.125");
  r100("1.135");
  return 0;
}

 1.115 1.115000009537e+00 1.120000004768e+00  
 1.125 1.125000000000e+00 1.129999995232e+00
 1.135 1.134999990463e+00 1.139999985695e+00

"1.11"은 1.11과 1.12 사이의 "반쪽"이지만,float값은 다음과 같습니다.1.115000009537...그리고 더 이상 "반쪽"이 아니라 1.12에 가깝고 가장 가까운 곳에 반올림합니다.float1.120000004768...

"1.125"는 1.12와 1.13 사이의 "반쪽"으로 변환됩니다.float이 값은 정확하게1.125'반쪽'입니다.짝수 규칙과의 연계에 의해 1.13을 향해 반올림하고 가장 가까운 값으로 반올림합니다.float1.129999995232...

"1.135"는 1.13과 1.14 사이의 "반쪽"이지만 변환 시float값은 다음과 같습니다.1.134999990463...그리고 더 이상 "반쪽"이 아니라 1.13에 가깝고 가장 가까운 곳에 반올림합니다.float1.129999995232...

코드가 사용되고 있는 경우

y = roundf(x*100.0f)/100.0f;

"1.135"는 1.13과 1.14 사이의 "반쪽"이지만 변환 시float값은 다음과 같습니다.1.134999990463...더 이상 '반쪽'이 아니라 1.13에 가깝지만 잘못 반올림하여float1.139999985695...정밀도가 더 낮기 때문에float대.double이 잘못된 값은 코딩 목표에 따라 올바른 값으로 간주될 수 있습니다.

double f_round(double dval, int n)
{
    char l_fmtp[32], l_buf[64];
    char *p_str;
    sprintf (l_fmtp, "%%.%df", n);
    if (dval>=0)
            sprintf (l_buf, l_fmtp, dval);
    else
            sprintf (l_buf, l_fmtp, dval);
    return ((double)strtod(l_buf, &p_str));

}

여기서n소수점 수

예:

double d = 100.23456;

printf("%f", f_round(d, 4));// result: 100.2346

printf("%f", f_round(d, 2));// result: 100.23

이 함수는 숫자와 정밀도를 가져와서 반올림된 숫자를 반환합니다.

float roundoff(float num,int precision)
{
      int temp=(int )(num*pow(10,precision));
      int num1=num*pow(10,precision+1);
      temp*=10;
      temp+=5;
      if(num1>=temp)
              num1+=10;
      num1/=10;
      num1*=10;
      num=num1/pow(10,precision+1);
      return num;
}

점을 왼쪽으로 이동하고 5개 이상의 조건을 확인하여 부동 소수점 번호를 int로 변환합니다.

언급URL : https://stackoverflow.com/questions/1343890/how-do-i-restrict-a-float-value-to-only-two-places-after-the-decimal-point-in-c

반응형