Java 에는 부호 없는 native 정수 타입이 없다.

Java 8에 와서야 부호 없는 정수를 처리하기 위한 메서드 몇 개가 추가되었다.

예를 들어, String을 native 타입 number로 변환하는 스태틱 메서드

        Long.parseUnsignedLong(String),  Integer.parseUnsignedint(String),

       Short.parseUnsignedShort(String),  Byte.parseUnsignedByte(String),

들과 역으로 native 타입 number를 String으로 변환하는 스태틱 메서드

        Long.toUnsignedString(long),  Integer.toUnsignedString(int)

가 있는데 이들은 타입 캐스팅할 댸 주의해야 할 부분이 있다.

아래의 Java 소스는 overflow 와 관련하여 심각한 문제가 발생할 수

있음을 보여 준다.

 

 

//  Filename: About_Java_Native_Number.java
//
//       Re-consider Java's native numbers (int or long or double) near to theirs maximal valuea
//
//
//  Compile: javac -d . About_Java_Native_Number.java
//  Execute: java About_Java_Native_Number
//
//
// Date: 2023.10.22


public class About_Java_Native_Number
{

    public static void main(String[] args)
    { 
        System.out.printf("What is pow(2, 30) = 2**30 (using Python's integer power operator expression)\n");
        System.out.printf("                   = 1 << 30 (using intege's shift opertor expression)\n");
        System.out.printf("                   = 2^30 (in LaTeX' math expression)\n");
        System.out.printf("\n");

        System.out.printf("Math.pow(2, 30) == %s\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %e\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %.9e\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %g\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %.0g\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %.9g\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %f\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %.0f\n", Math.pow(2, 30));
        System.out.printf("Math.pow(2, 30) == %a\n", Math.pow(2, 30));
        System.out.printf("\n");

        System.out.printf("1 << 30 = %d\n", 1 << 30);
        System.out.printf("(1 << 30) + (1 << 30) = %d\n", (1 << 30) + (1 << 30) );
        System.out.printf("(1 << 30)*2 = %d\n", (1 << 30)*2);
        System.out.printf("1 << (1 << 30) << 1 = %d\n", (1 << 30) << 1 );
        System.out.printf("0x7FFFFFFF = %d\n", 0x7FFFFFFF);
        System.out.printf("0x7FFFFFFF + 1 = %d\n", 0x7FFFFFFF + 1);
        System.out.printf("0x7FFFFFFF + 2 = %d\n", 0x7FFFFFFF + 2);
        System.out.printf("0x7FFFFFFF + 2 = %d\n", 0x7FFFFFFF + 2);
        System.out.printf("0x7FFFFFFF + 1 - 1 = %d\n", 0x7FFFFFFF + 1 - 1);
        System.out.printf("0x7FFFFFFF + 2 - 2 = %d\n", 0x7FFFFFFF + 2 - 2);
        System.out.printf("0x7FFFFFFF + 3 - 3 = %d\n", 0x7FFFFFFF + 3 - 3);
        System.out.printf("\n");

        System.out.printf("Is it true that (0x7FFFFFFF + 1) - 1 = (%d + 1) - 1 = %d - 1 = %d ?\n", 0x7FFFFFFF, 0x7FFFFFFF + 1, (0x7FFFFFFF + 1) - 1);
        System.out.printf("Is it true that (0x7FFFFFFF + 2) - 2 = (%d + 2) - 2 = %d - 2 = %d ?\n", 0x7FFFFFFF, 0x7FFFFFFF + 2, (0x7FFFFFFF + 1) - 2);
        System.out.printf("Is it true that (0x7FFFFFFF + 3) - 3 = (%d + 3) - 3 = %d - 3 = %d ?\n", 0x7FFFFFFF, 0x7FFFFFFF + 3, (0x7FFFFFFF + 1) - 3);
        System.out.printf("\n");

        System.out.printf("It is true that 1 << 30 = %d\n", 1 << 30);
        System.out.printf("But, is it true that (1 << 30)*2/2 = (%d)*2/2 = %d/2 = %d ?\n", 1 << 30, (1 << 30)*2,  (1 << 30)*2/2);
        System.out.printf("And, is it true that (1 << 30)*2/4 = (%d)*2/4 = %d/4 = %d ?\n", 1 << 30, (1 << 30)*2,  (1 << 30)*2/4);
        System.out.printf("And, is it true that (1 << 30)*2/8 = (%d)*2/8 = %d/8 = %d ?\n", 1 << 30, (1 << 30)*2,  (1 << 30)*2/8);
        System.out.printf("\n");

        System.out.printf("Also, is it true that (1 << 30)*4/2 = (%d)*4/2 = %d/2 = %d ?\n", 1 << 30, (1 << 30)*4,  (1 << 30)*4/2);
        System.out.printf("Also, is it true that ((1 << 30)*4 + 1234567)/2 = ((%d)*4 + 1234567)/2 = (%d + 1234567)/2 = %d ?\n", 1 << 30, (1 << 30)*4,  ((1 << 30)*4 + 1234567)/2);
        System.out.printf("Then, is it true that (Math.pow(2, 30)*4 + 1234567)/2 = ((%.0f)*4 + 1234567)/2 = (%.0f + 1234567)/2 = %.0f ?\n", Math.pow(2, 30), Math.pow(2, 30)*4,  (Math.pow(2, 30)*4 + 1234567)/2);


        System.out.printf("In is known that Math.pow(2, 30) == (1 << 30) ? %s\n", Math.pow(2, 30) == (1 << 30));
        System.out.printf("\n");

        System.out.printf("Long.toUnsignedString((byte)0xFFL) = %s\n", Long.toUnsignedString((byte)0xFFL));
        System.out.printf("Long.toUnsignedString(0xFFL) = %s\n", Long.toUnsignedString(0xFFL));
        System.out.printf("Integer.toUnsignedString((byte)0xFFL) = %s\n", Integer.toUnsignedString((byte)0xFFL));
        System.out.printf("Integer.toUnsignedString(0xFF) = %s\n", Integer.toUnsignedString(0xFF));
        System.out.printf("Integer.toUnsignedString(0xFFFFFFFFFF) = %s\n", Integer.toUnsignedString(0xFFFFFFFF));
        System.out.printf("Long.toUnsignedString(0xFFFFFFFFFF) = %s\n", Long.toUnsignedString(0xFFFFFFFF));
        System.out.printf("Long.toUnsignedString(0x100000000L) = %s\n", Long.toUnsignedString(0x100000000L));
        System.out.printf("Long.toUnsignedString(0xFFFFFFFFFFFFFFFFL) = %s\n", Long.toUnsignedString(0xFFFFFFFFFFFFFFFFL));
        System.out.printf("Long.toUnsignedString(0x8000000000000000L) = %s\n", Long.toUnsignedString(0x8000000000000000L));
        System.out.printf("Long.toString(0xFFFFFFFFFFFFFFFFL) = %s\n", Long.toString(0xFFFFFFFFFFFFFFFFL));
        System.out.printf("Long.toString(0x8000000000000000L) = %s\n", Long.toString(0x8000000000000000L));
        System.out.printf("\n");

    }
}

/*
---------
 Output:
---------

What is pow(2, 30) = 2**30 (using Python's integer power operator expression)
                   = 1 << 30 (using intege's shift opertor expression)
                   = 2^30 (in LaTeX' math expression)

Math.pow(2, 30) == 1.073741824E9
Math.pow(2, 30) == 1.073742e+09
Math.pow(2, 30) == 1.073741824e+09
Math.pow(2, 30) == 1.07374e+09
Math.pow(2, 30) == 1e+09
Math.pow(2, 30) == 1.07374182e+09
Math.pow(2, 30) == 1073741824.000000
Math.pow(2, 30) == 1073741824
Math.pow(2, 30) == 0x1.0p30

1 << 30 = 1073741824
(1 << 30) + (1 << 30) = -2147483648
(1 << 30)*2 = -2147483648
1 << (1 << 30) << 1 = -2147483648
0x7FFFFFFF = 2147483647
0x7FFFFFFF + 1 = -2147483648
0x7FFFFFFF + 2 = -2147483647
0x7FFFFFFF + 2 = -2147483647
0x7FFFFFFF + 1 - 1 = 2147483647
0x7FFFFFFF + 2 - 2 = 2147483647
0x7FFFFFFF + 3 - 3 = 2147483647

Is it true that (0x7FFFFFFF + 1) - 1 = (2147483647 + 1) - 1 = -2147483648 - 1 = 2147483647 ?
Is it true that (0x7FFFFFFF + 2) - 2 = (2147483647 + 2) - 2 = -2147483647 - 2 = 2147483646 ?
Is it true that (0x7FFFFFFF + 3) - 3 = (2147483647 + 3) - 3 = -2147483646 - 3 = 2147483645 ?

It is true that 1 << 30 = 1073741824
But, is it true that (1 << 30)*2/2 = (1073741824)*2/2 = -2147483648/2 = -1073741824 ?
And, is it true that (1 << 30)*2/4 = (1073741824)*2/4 = -2147483648/4 = -536870912 ?
And, is it true that (1 << 30)*2/8 = (1073741824)*2/8 = -2147483648/8 = -268435456 ?

Also, is it true that (1 << 30)*4/2 = (1073741824)*4/2 = 0/2 = 0 ?
Also, is it true that ((1 << 30)*4 + 1234567)/2 = ((1073741824)*4 + 1234567)/2 = (0 + 1234567)/2 = 617283 ?
Then, is it true that (Math.pow(2, 30)*4 + 1234567)/2 = ((1073741824)*4 + 1234567)/2 = (4294967296 + 1234567)/2 = 2148100932 ?
In is known that Math.pow(2, 30) == (1 << 30) ? true

Long.toUnsignedString((byte)0xFFL) = 18446744073709551615
Long.toUnsignedString(0xFFL) = 255
Integer.toUnsignedString((byte)0xFFL) = 4294967295
Integer.toUnsignedString(0xFF) = 255
Integer.toUnsignedString(0xFFFFFFFFFF) = 4294967295
Long.toUnsignedString(0xFFFFFFFFFF) = 18446744073709551615
Long.toUnsignedString(0x100000000L) = 4294967296
Long.toUnsignedString(0xFFFFFFFFFFFFFFFFL) = 18446744073709551615
Long.toUnsignedString(0x8000000000000000L) = 9223372036854775808
Long.toString(0xFFFFFFFFFFFFFFFFL) = -1
Long.toString(0x8000000000000000L) = -9223372036854775808
*/

 

 

 

 

Posted by Scripter
,

정수부의 자리수가 조금 큰 부동소수점수(64비트 double 포맷의 수)를 십진수 표현으로 출력해 보았습니다.

십진수로 표현하면  유효자리수 개수가 약 14~15개 정도인데,

Java 언어와 C# 언어에서는 유효수자를 적당한 개수(17개나 15개)로 자르고

그 뒤를 모두 0으로 출력하였지만,

C++ 언어에서는 유효수자 아래 부분을 자르지 않고 모두 출력합니다.

Pyhon, Ruby 언어에서도 C/C++ 언어 처럼 유효수자 아래 부분을 0으로 채우지 않습니다.

 

물론 Java, C#, Python, C, C++ 어느 프로그램 언어든

십진수로 표현할 때 자르는 방법이나 유효수자 아래 부분을 채우는 방법은 다르지만,

덧셈, 뺄셈, 곱셈, 나누셈, 기타 등등에서 유효수자 아래부분의 처리 결과는 대동소이합니다.

 

C++ 언어에서 긴 자리 정수를 처리하기 위해

gmplib 를 Visual C/C++ 용으로 개조한  mpir 라이브러리를 사용하였습니다.

 

// Filename: Test_Of_Native_Double_CPP_01.cpp
//
//
// Compile: cl /utf-8 /EHsc /I. Test_Of_Native_Double_CPP_01.cpp mpir.lib mpirxx.lib
// Execute: Test_Of_Native_Double_CPP_01
// Output:
//                            pow(2, 128) = 340282366920938463463374607431768211456.000000
//                            pow(2, 128) = 340282366920938463463374607431768211456
//     After mpz_pow(r, 2, 128), we get r = 340282366920938463463374607431768211456
//     Let b = 18446744073709551616 = 0x10000000000000000
//     Then we get b * b = 340282366920938463463374607431768211456 = 0x100000000000000000000000000000000
//
//
//  ------------------------------------------------------
//  출처: https://scripting.tistory.com/
//  ------------------------------------------------------


#include <cstdio>
#include <cmath>

#include <mpir.h>
#include <mpirxx.h>

#include <iostream>


using namespace std;

void test_01() 
{
      double y = pow(2, 128);
      printf("                       pow(2, 128) = %f\n", y);
      printf("                       pow(2, 128) = %.f\n", y);
         
    
    mpz_t r, a;

    mpz_init (r);
    mpz_init_set_str(a, "2", 0);

    mpz_pow_ui(r, a, 128);

    gmp_printf("After mpz_pow(r, %Zd, 128), we get r = %Zd\n", a, r);


    mpz_clear(r);
    mpz_clear(a);
    
    mpz_class b, c;


    b = "0x10000000000000000";
    c = b * b;

    cout << "Let b = " << b << " = " << hex << showbase << b << dec << noshowbase << endl;
    cout << "Then we get b * b = " << c << " = " << hex << showbase << c << dec << noshowbase << endl;

                  
}
    
int main(int argc, const char *argv[])
{
    test_01();
    printf("\n");
}

 

 

 

Posted by Scripter
,

정수부의 자리수가 조금 큰 부동소수점수(64비트 double 포맷의 수)를 십진수 표현으로 출력해 보았습니다.

십진수로 표현하면  유효자리수 개수가 약 14~15개 정도인데,

Java 언어와 C# 언어에서는 유효수자 개수로 자르고 그 뒤를 모두 0으로 출력지만,

Ruby 언어에서는 Python, C/C++ 언어들 처럼 유효수자 아래 부분을 자르지 않고 모두 츨력합니다.

 

물론 Java, C#, Python, C, C++ 어느 프로그램 언어든

십진수로 표현할 때 자르는 방법이나 유효수자 아래 부분을 채우는 방법은 다르지만,

덧셈, 뺄셈, 곱셈, 나누셈, 기타 등등에서 유효수자 아래부분의 처리 결과는 대동소이합니다.

 

 

 

# -*- coding: utf-8 -*-
#
# Filename: Test_Of_Native_Double_Precison_01.rb
#
#
# Execute: ruby Test_Of_Native_Double_Precison_01.rb
# Output:
#            2.pow(128) = 340282366920938463463374607431768211456.000000
#            2.pow(128) = 340282366920938463463374607431768211456
#                2**128 = 340282366920938463463374607431768211456
#         2**64 * 2**64 = 340282366920938463463374607431768211456
#
#
#  ------------------------------------------------------
#  출처: https://scripting.tistory.com/
#  ------------------------------------------------------


def test_01()
    y = 2.pow(128)
    print("       2.pow(128) = %f\n" % y)
    print("       2.pow(128) = %.f\n"% y)

    z = 2**128
    print("           2**128 = %d\n" % z)
    print("    2**64 * 2**64 = %d\n" % (2**64 * 2**64))
end
    

test_01()
print

 

 

Posted by Scripter
,

정수부의 자리수가 조금 큰 부동소수점수(64비트 double 포맷의 수)를 십진수 표현으로 출력해 보았습니다.

십진수로 표현하면  유효자리수 개수가 약 14~15개 정도인데,

Java 언어와 C# 언어에서는 유효수자를 적당한개수(17개나 15개)로 자르고

그 뒤를 모두 0으로 출력하였지만,

C 언어에서는 유효수자 아래 부분을 자르지 않고 모두 출력합니다.

Pyhon 언어에서도 C 언어 처럼 유효수자 아래 부분을 0으로 채우지 않습니다.

 

물론 Java, C#, Python, C, C++ 어느 프로그램 언어든

십진수로 표현할 때 자르는 방법이나 유효수자 아래 부분을 채우는 방법은 다르지만,

덧셈, 뺄셈, 곱셈, 나누셈, 기타 등등에서 유효수자 아래부분의 처리 결과는 대동소이합니다.

 

C 언어에서 긴 자리 정수를 처리하기 위해

gmplib 를 Visual C/C++ 용으로 개조한  mpir 라이브러리를 사용하였습니다.

 

// Filename: Test_Of_Native_Double_01.c
//
//
// Compile: cl /utf-8 /EHsc /I. Test_Of_Native_Double_01.c mpir.lib
// Execute: Test_Of_Native_Double_01
// Output:
//                            pow(2, 128) = 340282366920938463463374607431768211456.000000
//                            pow(2, 128) = 340282366920938463463374607431768211456
//     After mpz_pow(r, 2, 128), we get r = 340282366920938463463374607431768211456
//
//
//  ------------------------------------------------------
//  출처: https://scripting.tistory.com/
//  ------------------------------------------------------


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

#include <mpir.h>


void test_01() 
{
      double y = pow(2, 128);
      printf("                       pow(2, 128) = %f\n", y);
      printf("                       pow(2, 128) = %.f\n", y);        
    
    mpz_t r, a;

    mpz_init (r);
    mpz_init_set_str(a, "2", 0);

    mpz_pow_ui(r, a, 128);

    gmp_printf("After mpz_pow(r, %Zd, 128), we get r = %Zd\n", a, r);


    mpz_clear(r);
    mpz_clear(a);
                  
}
    
int main(int argc, const char *argv[])
{
    test_01();
    printf("\n");
}

 

 

 

Posted by Scripter
,

정수부의 자리수가 조금 큰 부동소수점수(64비트 double 포맷의 수)를 십진수 표현으로 출력해 보았습니다.

십진수로 표현하면  유효자리수 개수가 약 14~15개 정도인데,

Java 언어로는 유효수자 개수를 17개로 자르고 그 뒤를 모두 0으로 출력하였지만,

C# 언어로는 유효수자 아래 부분을 15개로 자르고 그 뒤를 모두 0으로 출력합니다.

Pyhon 은 C/C++ 의 경우 처럼 유효수자 아래 부분을 0으로 채우지 않습니다.

 

물론 Java, C#, Python, C, C++ 어느 프로그램 언어든

십진수로 표현할 때 자르는 방법이나 유효수자 아래 부분을 채우는 방법은 다르지만,

덧셈, 뺄셈, 곱셈, 나누셈, 기타 등등에서 유효수자 아래부분의 처리 결과는 대동소이합니다.

 

 

// Filename: Test_Of_Native_Double_Precison_01.cs
//
//
// Compile: csc Test_Of_Native_Double_Precison_01.cs /r:System.Numerics.dll
// Execute: Test_Of_Native_Double_Precison_01
// Output:
//                          Math.Pow(2, 128) = 340282366920938000000000000000000000000.00
//                          Math.Pow(2, 128) = 340282366920938000000000000000000000000
//     BigInteger.Pow(new BigInteger(2).128) = 340282366920938463463374607431768211456
//
//
//  ------------------------------------------------------
//  출처: https://scripting.tistory.com/
//  ------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Collections;
using System.Numerics;


public class Test_Program_Of_Native_Double
{
    public static void Test_01() 
    {
          double y = Math.Pow(2, 128);
          Console.WriteLine("                     Math.Pow(2, 128) = {0:F}", y);
          Console.WriteLine("                     Math.Pow(2, 128) = {0:F0}", y);

          BigInteger z = BigInteger.Pow(new BigInteger(2), 128);
          Console.WriteLine("BigInteger.Pow(new BigInteger(2).128) = {0}", z);
    }
    
    public static void Main(string[] args)
    {
        Test_01();
        Console.WriteLine();
    }
}

 

 

 

Posted by Scripter
,

정수부의 자리수가 조금 큰 부동소수점수(64비트 double 포맷의 수)를 십진수 표현으로 출력해 보았습니다.

십진수로 표현하면  유효자리수 개수가 약 14~15개 정도인데,

Java 언어로는 유효수자 개수를 17개로 자르고 그 뒤를 모두 0으로 출력하였고,

C# 언어로는 유효수자 개수를 15개로 자르고 그 뒤를 모두 0으로 출력하였지만,

Python 언어로는 유효수자 아래 부분을 자르지 않고 모두 츨력합니다.

Pyhon 은 C/C++ 의 경우와 비슷합니다.

 

물론 Java, C#, Python, C, C++ 어느 프로그램 언어든

십진수로 표현할 때 자르는 방법이나 유효수자 아래 부분을 채우는 방법은 다르지만,

덧셈, 뺄셈, 곱셈, 나누셈, 기타 등등에서 유효수자 아래부분의 처리 결과는 대동소이합니다.

 

# -*- coding: utf-8 -*-
#
# Filename: Test_Of_Native_Double_Precison_01.py
#
#
#
# Execute: python Test_Of_Native_Double_Precison_01.py
# Output:
#     math.pow(2, 128) = 340282366920938463463374607431768211456.000000
#     math.pow(2, 128) = 340282366920938463463374607431768211456
#               2**128 = 340282366920938463463374607431768211456
#
#
#  ------------------------------------------------------
#  출처: https://scripting.tistory.com/
#  ------------------------------------------------------


import math

def test_01():
    y = math.pow(2, 128)
    print("math.pow(2, 128) = %f" % y)
    print("math.pow(2, 128) = %.f"% y)

    z = 2**128
    print("          2**128 = %d" % z)

    
if __name__ == "__main__":
    test_01()
    print("")

 

 

Posted by Scripter
,

정수부의 자리수가 조금 큰 부동소수점수(64비트 double 포맷의 수)를 십진수 표현으로 출력해 보았습니다.

십진수로 표현하면  유효자리수 개수가 약 14~15개 정도인데,

17개로 자르고 그 뒤는 모두 0으로 출력합니다.

C# 의 것과 비슷하지만 자르는 유효수자 개수가 다릅니다.

Pyhon 이나 C/C++ 의 경우는 자르지 않고 소수점 위 부분을 모두 출력합니다.

 

물론 Java, C#, Python, C, C++ 어느 프로그램 언어든

십진수로 표현할 때 자르는 방법이나 유효수자 아래 부분을 채우는 방법은 다르지만,

덧셈, 뺄셈, 곱셈, 나누셈, 기타 등등에서 유효수자 아래부분의 처리 결과는 대동소이합니다.

 

 

// Filename: Test_Of_Native_Double_Precison_001.java
//
//
// Compile: javac -d . Test_Of_Native_Double_Precison_001.java
// Execute: java Test_Of_Native_Double_Precison_001
// Output:
//                 Math.pow(2, 128) = 340282366920938460000000000000000000000.000000
//                 Math.pow(2, 128) = 340282366920938460000000000000000000000
//     new BigInteger("2").pow(128) = 340282366920938463463374607431768211456
//
//
//  ------------------------------------------------------
//  출처: https://scripting.tistory.com/
//  ------------------------------------------------------


import java.math.BigInteger;
import java.util.Arrays;

public class Test_Of_Native_Double_Precison_001
{
    public static void test_01() 
    {
          double y = Math.pow(2, 128);
          System.out.printf("            Math.pow(2, 128) = %f\n", y);
          System.out.printf("            Math.pow(2, 128) = %.0f\n", y);

          BigInteger z = new BigInteger("2").pow(128);
          System.out.printf("new BigInteger(\"2\").pow(128) = %s\n", z);
    }
    
    public static void main(String[] args)
    {
        test_01();
        System.out.println();
    }
}
Posted by Scripter
,

 

10**100 을 7로 나누고 다시 7을 곱해 보았습니다.

 math.floor() 함수는 유효숫자의 개수 때문에 오차가 좀(?) 많네요.

(float 인스턴스).as_integer_ratio()  메서드로도 확인해 보았습니다.

 

 

>>> import math

>>> help(math.floor)
Help on built-in function floor in module math:

floor(x, /)
    Return the floor of x as an Integral.

    This is the largest integer <= x.
>>> math.floor(1.0/7*1.0E100)*7
9999999999999999916195299569383046603428070211005418059480472676230398615693829843450434335205752832
>>> 10**100 // 7
1428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428571428
>>> 10**100 // 7 * 7
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999996
>>> (0.7*1E100).as_integer_ratio()
(6999999999999999528519570100600705052013993947706024980124877574781630764975543820898143428537221120, 1)

 

 

 

 

 

 

Posted by Scripter
,

어떤 프로그램 언어를 쓰든 0.1 + 0.2 ≠ 0.3 이 되는 것이 당연(?)합니다.

또한 1.0/(0.1 + 0.2 - 0.3)   ∞ 이 되는 것도 당연(?)합니다.

>>> 0.1 + 0.2 - 0.3
5.551115123125783e-17
>>> 0.1 + 0.2 - 0.3 > 1.0E-17
True
>>> 0.1 + 0.2 - 0.3 > 1.0/10E17
True

0.1 + 0.2 - 0.3 이 1.0E-17 즉 0.000000000000000001 보다 크다고 합니다.

 

이래 가지고서는 부동소수점수의 계산 결과를 어디 까지 믿을 수

있는지 의문입니다.

(보통으로는 배정밀도 부동소수점수는 유효수자 개수가 14개~15개 정도입니다.)

 

다행히 Python 의 fractions 모듈과 decimal 모듈을 사용하면

이런 오류를 쉽게 복구할 수 있습니다.

아래는 Python 3 인터프리터로 실행한 결과입니다.

(fractions.Fraction 객체).limit_denominator() 가 문제 해결의 핵심입니다.

(조금 번거럽네요.)

 

>>> import fractions, decimal, math
>>> a = fractions.Fraction(0.1)
>>> b = fractions.Fraction(0.2)
>>> c = fractions.Fraction(0.3)
>>> a + b == c
False
>>> 0.1 + 0.2 == 0.3
False
>>> a + b > c
True
>>> 0.1 + 0.2 > 0.3
True
>>> a + b - c
Fraction(1, 36028797018963968)
>>> 0.1 + 0.2 - 0.3
5.551115123125783e-17
>>> a2 = a.limit_denominator()
>>> b2 = b.limit_denominator()
>>> c2 = c.limit_denominator()
>>> a2, b2, c2
(Fraction(1, 10), Fraction(1, 5), Fraction(3, 10))
>>> a, b, c
(Fraction(3602879701896397, 36028797018963968), Fraction(3602879701896397, 18014398509481984), Fraction(5404319552844595, 18014398509481984))
>>> a2 + b2
Fraction(3, 10)
>>> "%s" % (a2 + b2)
'3/10'
>>> print("%s" % (a2 + b2))
3/10
>>> c2
Fraction(3, 10)
>>> "%s" % (c2)
'3/10'
>>> print("%s" % (c2))
3/10
>>> a2 + b2 == c2
True
>>> a2 + b2 - c2
Fraction(0, 1)
>>> print(a2 + b2 - c2)
0
>>> print("%s" % (a2 + b2 - c2))
0
>>> print("%d" % (a2 + b2 - c2))
0
>>> print("%d" % (a2 + b2))
0
>>> print("%d" % (c2))
0

 

 

Posted by Scripter
,

부동소수점수에 '를 붙이면 가독성이 좋아 실수를 덜 합니다.

아래의 소스는 MSVC 와 g++ 로 잘 컴파일되고 동일한 실행 결과를 얻습니다.

// Filename: test_cpp_literal.cpp
//
// Compile: cl /utf-8 /EHsc test_cpp_literal.cpp
// Execute: test_cpp_literal
//
//            Or
//
// Compile: g++ -o test_cpp_literal test_cpp_literal.cpp
// Execute:./test_cpp_literal
//
// Output:
//     pie =
//     3.14159
//     3.14159
//     3.141593
//     3.141593e+00
//
//       pie =
//       3.141593
//       3.14159
//       3.141593
//       3.141593e+00
//
//     ee =
//     2.71828
//     2.71828
//     2.718280
//     2.718280e+00
// 
//       ee =
//       2.71828
//       2.71828
//       2.718280
//       2.718280e+00
//
//
// Date: 2023.01.03
//
// Copyright (c) 2023 scrpting.tistory.com
// Liscense: BSD-3


#include <iostream>
#include <iomanip>     // for std::setprecision()
#include <cstdio>

using namespace std;

#if defined(__cplusplus)
double pie = 3.141'593;
#endif

int main()
{
    cout << "pie = " << endl;
    cout << pie << endl;
    printf("%g\n", pie);
    printf("%f\n", pie);
    printf("%e\n", pie);
    cout << endl;

    cout << "  pie = " << endl;
    cout << "  " << setprecision(10) << pie << endl;
    printf("  %lg\n", pie);
    printf("  %lf\n", pie);
    printf("  %le\n", pie);
    cout << endl;

#if defined(__cplusplus)
double ee = 2.718'28;
#endif

    cout << "ee = " << endl;
    cout << ee << endl;
    printf("%g\n", ee);
    printf("%f\n", ee);
    printf("%e\n", ee);
    cout << endl;

    cout << "  ee = " << endl;
    cout << "  " << setprecision(10) << ee << endl;
    printf("  %lg\n", ee);
    printf("  %lf\n", ee);
    printf("  %le\n", ee);
    cout << endl;

    return 0;
}

 

 

 

 

Posted by Scripter
,