web-dev-qa-db-ja.com

Cでフロートを丸める関数はありますか、自分で書く必要がありますか?

Cでフロートを丸める関数はありますか、自分で書く必要がありますか?

float conver = 45 .59 2346543;

実際の値を小数点以下1桁に変換します。conver= 45。6

25
T.T.T.

ロブが述べたように、おそらくフロートを小数点以下1桁にprintしたいだけです。この場合、次のようなことができます。

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

int main()
{
  float conver = 45.592346543;
  printf("conver is %0.1f\n",conver);
  return 0;
}

格納された値を実際に丸めたい場合、それはもう少し複雑です。たとえば、1桁の1桁の表現では、浮動小数点の正確なアナログがほとんどありません。できるだけ近くにしたい場合は、次のような方法で問題を解決できます。

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

int main()
{
  float conver = 45.592346543;
  printf("conver is %0.1f\n",conver);

  conver = conver*10.0f;
  conver = (conver > (floor(conver)+0.5f)) ? ceil(conver) : floor(conver);
  conver = conver/10.0f;

  //If you're using C99 or better, rather than ANSI C/C89/C90, the following will also work.
  //conver = roundf(conver*10.0f)/10.0f;

  printf("conver is now %f\n",conver);
  return 0;
}

この2番目の例はあなたが探しているものではないでしょうが、完全を期すために含めました。出力だけでなく内部的にこの方法で数値を表現する必要がある場合は、代わりに 固定小数点表現 の使用を検討してください。

28
Matt J

もちろん、roundf()を使用できます。小数点以下1桁に丸める場合は、次のようにします。roundf(10 * x) / 10

#include <math.h>

double round(double x);
float roundf(float x);

-lmとリンクすることを忘れないでください。 ceil()、floor()、trunc()もご覧ください。

2
Joao da Silva

丸められた値をprintするには、 @ Matt J が質問に適切に答えます。

float x = 45.592346543;
printf("%0.1f\n", x);  // 45.6

ほとんどの浮動小数点(FP)はbinaryベースであるため、exact1decimal数学的に正解がx.1, x.2, ...の場合、配置はできません。

FP数値をnearest0.1に変換することは別の問題です。

Overflow:10(または100、1000など)で最初にスケーリングするアプローチは、大きなxに対してオーバーフローする可能性があります。

float round_tenth1(float x) {
  x = x * 10.0f;
  ...
}

二重丸め:0.5fを追加してからfloorf(x*10.0f + 0.5f)/10.0を使用すると、中間合計x*10.0f + 0.5fが新しい整数に切り上げられたときに間違った結果が返されます。

// Fails to round 838860.4375 correctly, comes up with 838860.5 
// 0.4499999880790710449 fails as it rounds to 0.5
float round_tenth2(float x) {
  if (x < 0.0) {
    return ceilf(x*10.0f + 0.5f)/10.0f;
  }
  return floorf(x*10.0f + 0.5f)/10.0f;
}

intへのキャストには、float xINT_MAXよりもはるかに大きい場合に明らかな問題があります。


<math.h>で利用可能なroundf()とファミリを使用するのが最善のアプローチです。

float round_tenthA(float x) {
  double x10 = 10.0 * x;
  return (float) (round(x10)/10.0);
}

doubleの使用を避けるには、数値に丸めが必要かどうかをテストするだけです。

float round_tenthB(float x) {
  const float limit = 1.0/FLT_EPSILON;
  if (fabsf(x) < limit) {
    return roundf(x*10.0f)/10.0f;
  }
  return x;
}
1
chux

round()関数、およびfround()もあり、doubleで表された最も近い整数に丸められます。しかし、それはあなたが望むものではありません。

私は同じ問題を抱えており、これを書いた:

#include <math.h>

   double db_round(double value, int nsig)
/* ===============
**
** Rounds double <value> to <nsig> significant figures.  Always rounds
** away from zero, so -2.6 to 1 sig fig will become -3.0.
**
** <nsig> should be in the range 1 - 15
*/

{
    double     a, b;
    long long  i;
    int        neg = 0;


    if(!value) return value;

    if(value < 0.0)
    {
        value = -value;
        neg = 1;
    }

    i = nsig - log10(value);

    if(i) a = pow(10.0, (double)i);
    else  a = 1.0;

    b = value * a;
    i = b + 0.5;
    value = i / a;

    return neg ? -value : value;
} 
1
Christopher Bel

Robの答えを少し一般化するために、出力でnotを実行している場合でも、sprintf()で同じインターフェイスを使用できます。

ただし、別の方法があります。 ceil()およびfloor()を試して、切り上げと切り捨てを行うことができます。素敵なトリックは0.5を追加することです。そのため、0.5を超える値は切り上げられますが、その下の値は切り捨てられます。 ceil()floor()doublesでのみ機能します。

編集:また、フロートの場合、truncf()を使用してフロートを切り捨てることができます。正確な丸めを行うには、同じ+0.5のトリックが機能するはずです。

1
Chris Lutz

#define round(a)(int)(a + 0.5)をマクロとして使用できるため、round(1.6)を記述すると常に2を返し、round(1.3)を記述すると1を返します。

0
redblood