실수의 소수점 자릿수를 알 수 없을까요?

dltkddyd의 이미지

4.4
또는
4.4f

라는 데이터가 아래와 같이 float형 변수에 저장돼 있을 때,

float fl=4.4;

또는

float fl=4.4f;

소수점 아래 자릿수가 몇 개인지 알 수 있는 방법이 있을까요? 저 실수의 경우는 소수점 아래 자리수가 한 자리인데요, 만약 다음과 같이

float fl=4.432f;

라고 하면, 소수점 아래 자릿수는 세 자리입니다. 즉 3을 얻을 수 있는 방법이 없나요?

snowall의 이미지

반복문을 쓴다면 10을 곱하고 1로 나누어서 나머지가 0인지 따지는걸 반복해보면 됩니다.

피할 수 있을때 즐겨라! http://melotopia.net/b

세벌의 이미지

이론적으론 그런데 실제론 오차가 발생할겁니다. 예를 들어 3분의 1을 소수로 하면 0.333333.... 이런 식으로 끝없이 나가니 유한소수로 표현할 수가 없으니...

snowall의 이미지

물론 그렇습니다. 그러나 컴퓨터의 실수형에는 무한소수가 없으니까요.

피할 수 있을때 즐겨라! http://melotopia.net/b

snowall의 이미지

아니면 string으로 바꾼 후 소숫점.부터 끝까지 글자 수를 세도 되겠죠. 물론 뒤에서부터 가장 앞에 나오는 0까지입니다.

정규식으로도 소수 부분만 떼어낼 수 있을 것 같은데요.

피할 수 있을때 즐겨라! http://melotopia.net/b

snow의 이미지

 
snowall의 이미지

다음과 같이 하면 쉽겠군요

예를 들어 x=41.52350000라고 한다면

y=x%1
그럼 y=0.52350000이 들어갑니다. 만약 언어에 따라, 뒤에 있는 무의미한 0을 빼준다면 y=0.5235가 됩니다.

y를 string이라고 한다면 length(y)-2를 계산하면 4이겠죠. 그게 답이겠죠.

언어가 유효숫자를 중요하게 생각해서 0이 살아있는 경우에는 끝에 있는 0을 빼주면 되는데, 이건 금방 생각이 안나네요. 정규식으로 치환하면 될 것 같긴 한데...

피할 수 있을때 즐겨라! http://melotopia.net/b

jick의 이미지

실수는 2진수로 저장되기 때문에, 4.4처럼 2의 거듭제곱으로 나눠떨어지지 않는 수는 정확히 저장할 수 없습니다. 그러니까 실제로는 4.39999999999난 4.4000000001 뭐 이런 식으로 오차가 생깁니다.

"소숫점 아래 자릿수"를 기억하고 싶으면 실수형을 쓸 게 아니라 숫자를 10진수 형태로 저장하는 방법을 강구해야 할 겁니다.

dltkddyd의 이미지

I agree with you but can't find how to do so. Let me know how to do so.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

jick의 이미지

https://www.google.com/search?q=decimal+number+representation+library

뭐 이런 데서 출발하시면 되지 않을까요?

moldycake의 이미지

그냥 다 부동소수점으로 처리해버리는게 편해요~`

moldycake의 이미지

그냥 다 부동소수점으로 처리해버리는게 편해요~`

익명 사용자의 이미지

8년 전의 질문글 답변하기 ~_~

엄밀하게 답한다면, 이 질문에 대한 답은 "불가능"입니다.

Quote:
float fl=4.4f;

소수점 아래 자릿수가 몇 개인지 알 수 있는 방법이 있을까요? 저 실수의 경우는 소수점 아래 자리수가 한 자리인데요

그렇게 생각하나요? 유감이군요. 컴퓨터는 그렇게 동작하지 않는데요.

float이 IEEE754 단정밀도 부동소수점 타입이라면, fl에 저장될 값은 정확히 아래와 같습니다:

4 + 838861/2097152 = 4.400000095367431640625

왜 이렇게 저장되는지는 1) IEEE754는 수를 2진법으로 저장한다는 점, 2) 단정밀도 부동소수점이 저장할 수 있는 유효숫자의 수는 유한하고 한정되어 있다는 점, 그리고 결정적으로 3) 4.4는 이진법으로 나타내면 무한소수가 된다는 점 때문입니다.

결국 float는 4.4에 가장 가까운 표현 가능한 수를 저장하는 수밖에 없고, 위와 같은 결과가 발생하는 것이죠. 그런 이유로, 일단 값이 float 타입으로 변환되고 나면 4.4와 4.40000001를 구분할 방법도 없습니다: https://ideone.com/jp8caS

그러니 fl 변수의 값만 가지고는 소숫점 아래 자리수가 한 자리뿐이라는 걸 알 방법이 없는 것이죠.

대충 해결 방법이 두 가지 정도 떠오르는군요.

1) 유효 숫자 갯수가 어떤 적절한 범위 안이라는 힌트가 있으면 해결이 가능합니다.
예를 들어 4.400000095367431640625이라는 값이 주어지고, 유효숫자가 소숫점 아래 여섯 자리 이하라는 힌트가 있다면, 예컨대 10^6을 곱하고 가까운 정수로 반올림하여 (4400000) 10의 몇 거듭제곱의 배수인지 세고 (5), 6에서 그 값을 빼면 되겠죠. 1이 나오는군요.

원리는 뭐 간단합니다. 4.40000001와 같이 4.4에 너무 가까워서 같은 float 값으로 변환되는 다른 수들을 배제할 수 있게 되면, 해결할 수 있는 문제가 되는 거죠.

2) 그냥 float을 쓰지 마세요.

뭐 예컨대 char fl[] = "4.4"; 하면 끝입니다. 물론 이렇게 나타낸 숫자를 어떻게 계산에 활용하는지는 또 다른 문제입니다. -_-;;

소위 (엄밀히 말해 정확한 표현은 아니긴 합니다만) "무한 정밀도"로 숫자를 다룰 수 있는 숫자 라이브러리들이 있습니다. 귀하께서 유리수 범위에서 너무 멀리 벗어나지만 않는다면, 컴퓨터 메모리가 허용하는 한 귀하께서 다루는 숫자를 항상 정확하게 표현할 수 있죠. 몇몇 고급 언어들은 심지어 그런 라이브러리를 내장하기도 합니다.

그런 라이브러리를 활용할 수만 있다면 남은 문제는 뭐 간단하지요. 결과가 정수가 될 때까지 계속 10을 곱하면서 테스트하면 되니까요.

라스코니의 이미지

결론적으로 알수 없습니다.
float fl=4.432라고 했을 때 fl은 정확히 4.432라는 값을 가지고 있지 않을 수도 있습니다(가지고 있을 수도 있습니다). printf("%f", fl)로 출력했을 때 똑같이 표현할 수도 있고 아닐수도 있고요.

float 형은 대충 소수점 6째 자리부터 조금씩 달라지는 것 같고, double 형은 소수점 9째 자리(불확실함)부터 조금씩 달라지는데.... 결과적으로 보면 소수점 몇 자리까지 나오는 지 아는 것은 어떤 도움도 되지 않습니다. 어떤 상황에서 이런 정보가 필요한지 알고 싶네요.

slee0303의 이미지

소수점 몇 자리에서 달라지는 것이 아니고, 전체 유효숫자의 개수에 따라 달라집니다.
십진수 기준 float는 7자리 double 형은 15자리 정도이므로, 이러한 유효숫자 내에 있다면 소숫점 아래 100 자리 수도 나타낼 수 있습니다.
참고로, 0.1 등과 같은 대부분의 소수(분모에 2 이외의 다른 수가 들어가는 소수)는 이진수에서 무한 소수이므로 애당초 기계에 정확하게 입력할 수 없습니다.

해보지도 않고의 이미지

float형은 유효숫자가 소수 6째자리까지입니다. 따라서 소수 다섯째 자리까지는 확인 가능합니다. 왜냐하면 0으로 출력되니까요. 반올림을 하는 것도 아닙니다. 무조건 소수 6째자리까지는 보장합니다. 유효숫자의 개념을 잘 모르는 것 같아요. 아래는 대충해봤어요.

$ cat 1_1.c
#include <stdio.h>
 
void Print(char *str);
 
int main(void){
   char str[100];
   float f1=3.1;
   float f2=3.14;
   float f3=3.141;
   float f4=3.1415;
   float f5=3.14159;
   float f6=3.141592;
   float f7=3.1415926;
   float f8=3.14159265;
 
   sprintf(str, "%f", f1);
   Print(str);
   sprintf(str, "%f", f2);
   Print(str);
   sprintf(str, "%f", f3);
   Print(str);
   sprintf(str, "%f", f4);
   Print(str);
   sprintf(str, "%f", f5);
   Print(str);
   sprintf(str, "%f", f6);
   Print(str);
   sprintf(str, "%f", f7);
   Print(str);
   sprintf(str, "%f", f8);
   Print(str);
}
 
void Print(char *str){
   int cnt=0;
 
   printf("%s", str);
   while(*str++!='.');
   while(*str++!='0') cnt++;
   printf(" --> %d\n", cnt);
}
$ ./1_1
3.100000 --> 1
3.140000 --> 2
3.141000 --> 3
3.141500 --> 4
3.141590 --> 5
3.141592 --> 214
3.141593 --> 214
3.141593 --> 214
DarkSide의 이미지

윗 분께서 말씀하셨듯이, 유효숫자가 소수 6째자리까지가 아니고 소수점 관계 없이 7자리입니다.
때문에 유효 숫자 범위 내에서 제한적으로 확인 가능한 경우가 있을 뿐, 일반적으로는 불가능하다는 말이 맞습니다.
그리고 마지막 이진수 자리수는 이미 반올림이 된 상태이고, 여기에서 연속적으로 반올림이 될 수도 있습니다.
유효숫자 범위에 따라서 말이죠.
예를 들어 float 형에서 유효 숫자가 7개라면 12.356098 을 입력했을 때 실제로는 12.35610x 로 입력되겠죠.
그러면, 소숫점 아래 4개까지가 유효할까요, 5개까지가 유효할까요?

그러니까의 이미지

유효숫자 6자리까지 보장되니 5자리까지 확인 가능하가다거요. 그리고 6자리까지는 반올림안돼요. 7자리이후부터는 아무 의없는 숫자이니, 반올림이 되든 말든 알게 뭔가요. 7에서 6으로는 절대로 반올림 안됩니다.

소알못의 이미지

제대로 내용 좀 이해하고 씁시다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.