Kiểu dữ liệu float và double trong Java


220

Kiểu dữ liệu float là một điểm nổi 32-bit IEEE 754 có độ chính xác đơn và kiểu dữ liệu kép là một điểm nổi 64-bit IEEE 754 có độ chính xác kép.

Nó có nghĩa là gì? Và khi nào tôi nên sử dụng float thay vì double hay ngược lại?


8
Bạn nên sử dụng phao thay vì gấp đôi khi việc sử dụng bộ nhớ là rất quan trọng. Nếu bạn cần tính toán chính xác hơn, sử dụng gấp đôi.
Everv0id

12
@ Everv0id: Tôi không chắc chắn về bất kỳ tình huống nào trong đó bộ nhớ quá chặt đến nỗi người ta phải hy sinh độ chính xác cho không gian. (Bạn đang sử dụng Java , vì lợi ích của nó ...) Có thể có một số tình huống khi nó được yêu cầu, nhưng trong thực tế tôi đã thấy nó rất hiếm khi. Nếu bạn muốn giải thích lý do tại sao bạn tin rằng đây là một ý tưởng tốt, cung cấp một câu trả lời với một ví dụ sẽ là một bổ sung xứng đáng.
Makoto


5
@Makoto thực sự, tôi chưa bao giờ sử dụng phao, chỉ tăng gấp đôi. Nhưng có thể có các ứng dụng (về lý thuyết) sẽ giữ một lượng lớn số dấu phẩy động, do đó việc sử dụng bộ nhớ gấp đôi có thể rất quan trọng. Về lý thuyết, ofc; Trong thực tế, bạn luôn có thể mua một máy chủ khác .
Everv0id

3
Tôi đã sử dụng các số chính xác cố định 4 byte và thậm chí 2 byte để tiết kiệm bộ nhớ, nhưng trừ khi bạn có hàng tỷ trong số này thì không chắc là có giá trị. Thời gian bạn cần để viết "gấp đôi" thay vì "thả nổi" (nó có thêm một chữ cái) đáng giá hơn 1000 lần so với bộ nhớ bổ sung bạn sử dụng, nhưng nếu sử dụng doublethay vì floatcứu bạn khỏi một lỗi liên quan chính xác, thì nó đáng giá .
Peter Lawrey

Câu trả lời:


259

Các trang Wikipedia trên nó là một nơi tốt để bắt đầu.

Tóm lại:

  • floatđược biểu thị bằng 32 bit, với 1 bit dấu, 8 bit số mũ và 23 bit có nghĩa (hoặc những gì xuất phát từ số ký hiệu khoa học: 2.33728 * 10 12 ; 33728 là số có nghĩa).

  • double được biểu diễn bằng 64 bit, với 1 bit dấu, 11 bit số mũ và 52 bit có ý nghĩa.

Theo mặc định, Java sử dụng doubleđể biểu diễn các chữ số dấu phẩy động của nó (vì vậy một chữ 3.14được gõ double). Đây cũng là kiểu dữ liệu sẽ cung cấp cho bạn phạm vi số lớn hơn nhiều, vì vậy tôi rất khuyến khích việc sử dụng nó float.

Có thể có một số thư viện mà thực sự buộc việc bạn sử dụng float, nhưng nói chung - trừ khi bạn có thể đảm bảo rằng kết quả của bạn sẽ đủ nhỏ để vừa trong float's phạm vi quy định , sau đó nó là tốt nhất để lựa chọn với double.

Nếu bạn yêu cầu độ chính xác - ví dụ: bạn không thể có giá trị thập phân không chính xác (như 1/10 + 2/10) hoặc bạn đang làm bất cứ điều gì với tiền tệ (ví dụ: đại diện cho 10,33 đô la trong hệ thống), sau đó sử dụng một BigDecimal, có thể hỗ trợ số lượng chính xác tùy ý và xử lý các tình huống như thế một cách thanh lịch.


4
Chẳng phải 233728 == mantissa trong ví dụ đã cho sao? Ý tôi là, phần khác được lưu trữ ở đâu?
JaLoveAst1k

1
@ mathguy54: Trong ký hiệu khoa học, 2 sẽ là toàn bộ số nguyên và .33728 sẽ là mantissa. Đây là một tài liệu tham khảo cho điều đó.
Makoto

5
Tôi đã tìm kiếm thông tin trên phao và đôi và thấy điều này và cần bình luận: nếu bạn đang làm bất cứ điều gì với tiền tệ không liên quan đến xu phân số, sử dụng BigDecimal là vô lý. Tiền tệ phổ biến là dữ liệu rời rạc, vì vậy bạn nên sử dụng loại dữ liệu số nguyên. (Đây là một trong những lỗi phổ biến hơn do các lập trình viên trẻ - kể từ khi chúng tôi sử dụng một tách USD từ cent, họ nghĩ đó là một giá trị dấu chấm Nó không phải là...)
Trixie Wolf

2
@TrixieWolf, bạn có thể cụ thể hơn không, bạn có đề xuất sử dụng hai số nguyên (phần nguyên và phần thập phân) không? Và bạn đang nói về tiền tệ chung, còn lại thì sao? Một số lượng được đánh giá với 6 số thập phân, do đó bạn không thể đơn giản *100. Xin vui lòng, bạn có một điểm ở đây nhưng bạn có thể chính xác hơn :)
AxelH

9
@AxelH Ngoại trừ những vấn đề về tính toán tài chính nơi có thể tồn tại một phần xu, tiền luôn rời rạc. Bạn sẽ sử dụng một loại số nguyên để lưu trữ dữ liệu. Vì vậy, 5,34 đô la sẽ được lưu trữ dưới dạng 534. Phần đô la là val / 100 trong toán học số nguyên và xu là val% 100 trong toán học số nguyên, trong đó% đề cập đến phép toán còn lại. Đối với tiền có nhiều vị trí hơn số thập phân, nó vẫn nên được lưu trữ dưới dạng tích phân vì nó rời rạc. Ngay cả khi nó không rời rạc, thường thì bạn sẽ muốn sao lưu vào một bộ lưu trữ riêng biệt bởi vì nó chính xác vì vậy bạn sẽ không mất tiền cho các lỗi làm tròn.
Trixie Wolf

72

Một float cho bạn khoảng. Độ chính xác 6-7 chữ số thập phân trong khi gấp đôi cung cấp cho bạn khoảng. 15-16. Ngoài ra phạm vi số lớn hơn gấp đôi.

Một đôi cần 8 byte dung lượng lưu trữ trong khi float chỉ cần 4 byte.


13

Số dấu phẩy động, còn được gọi là số thực, được sử dụng khi đánh giá các biểu thức yêu cầu độ chính xác phân số. Ví dụ: các phép tính như căn bậc hai hoặc siêu việt như sin và cosin, dẫn đến một giá trị có độ chính xác yêu cầu loại dấu phẩy động. Java triển khai tập hợp các kiểu toán tử và toán tử dấu phẩy động chuẩn (IEEE IEEE 754). Có hai loại loại dấu phẩy động, float và double, tương ứng là các số chính xác đơn và kép. Chiều rộng và phạm vi của chúng được hiển thị ở đây:


   Name     Width in Bits   Range 
    double  64              1 .7e308 to 1.7e+308
    float   32              3 .4e038 to 3.4e+038


Phao nổi

Kiểu float xác định một giá trị độ chính xác đơn sử dụng 32 bit lưu trữ. Độ chính xác đơn nhanh hơn trên một số bộ xử lý và chiếm một nửa dung lượng so với độ chính xác gấp đôi, nhưng sẽ trở nên không chính xác khi các giá trị rất lớn hoặc rất nhỏ. Các biến kiểu float rất hữu ích khi bạn cần một thành phần phân số, nhưng không yêu cầu độ chính xác lớn.

Dưới đây là một số ví dụ khai báo biến float:

phao cao, lowtemp;


gấp đôi

Độ chính xác kép, như được biểu thị bằng từ khóa kép, sử dụng 64 bit để lưu trữ một giá trị. Độ chính xác kép thực sự nhanh hơn độ chính xác đơn trên một số bộ xử lý hiện đại đã được tối ưu hóa cho các phép tính toán học tốc độ cao. Tất cả các hàm toán học siêu việt, chẳng hạn như sin (), cos () và sqrt (), trả về giá trị kép. Khi bạn cần duy trì độ chính xác qua nhiều phép tính lặp hoặc đang thao túng các số có giá trị lớn, gấp đôi là lựa chọn tốt nhất.


Câu trả lời này để làm rõ khi nào chúng ta nên sử dụng float và double.why không?
Bạn giành chiến thắng

8
Cả floatcũng không doubleloại được sử dụng tốt nhất cho đồng tiền trong Java, vì họ mở ra cơ hội cho làm tròn lỗi. Bài viết này đi sâu vào chi tiết hơn: javapractices.com/topic/TopicAction.do?Id=13
PPartisan

1
"float có thể hữu ích khi đại diện cho đô la và xu." - không không không không không không không. Không bao giờ, lưu trữ tiền tệ như phao / đôi.
giảm hoạt động

2

Tuy nhiên, Java dường như có xu hướng sử dụng gấp đôi cho các tính toán:

Trong trường hợp chương trình tôi đã viết trước đó ngày hôm nay, các phương thức không hoạt động khi tôi sử dụng float, nhưng bây giờ hoạt động rất tốt khi tôi thay thế float bằng double (trong NetBeans IDE):

package palettedos;
import java.util.*;

class Palettedos{
    private static Scanner Z = new Scanner(System.in);
    public static final double pi = 3.142;

    public static void main(String[]args){
        Palettedos A = new Palettedos();
        System.out.println("Enter the base and height of the triangle respectively");
        int base = Z.nextInt();
        int height = Z.nextInt();
        System.out.println("Enter the radius of the circle");
        int radius = Z.nextInt();
        System.out.println("Enter the length of the square");
        long length = Z.nextInt();
        double tArea = A.calculateArea(base, height);
        double cArea = A.calculateArea(radius);
        long sqArea = A.calculateArea(length);
        System.out.println("The area of the triangle is\t" + tArea);
        System.out.println("The area of the circle is\t" + cArea);
        System.out.println("The area of the square is\t" + sqArea);
    }

    double calculateArea(int base, int height){
        double triArea = 0.5*base*height;
        return triArea;
    }

    double calculateArea(int radius){
        double circArea = pi*radius*radius;
        return circArea;
    }

    long calculateArea(long length){
        long squaArea = length*length;
        return squaArea;
    }
}

Tôi đã có cùng một vấn đề ngày hôm nay. Điều gì có thể là lý do đằng sau sự thiên vị này?
Shachi

2

Điều này sẽ đưa ra lỗi:

public class MyClass {
    public static void main(String args[]) {
        float a = 0.5;
    }
}

/MyClass.java:3: error: các loại không tương thích: có thể chuyển đổi mất mát từ double sang float float a = 0.5;

Điều này sẽ làm việc hoàn toàn tốt

public class MyClass {
    public static void main(String args[]) {
        double a = 0.5;
    }
}

Điều này cũng sẽ làm việc hoàn toàn tốt

public class MyClass {
    public static void main(String args[]) {
        float a = (float)0.5;
    }
}

Lý do : Java theo mặc định lưu trữ số thực là gấp đôi để đảm bảo độ chính xác cao hơn.

Double chiếm nhiều không gian hơn nhưng chính xác hơn trong quá trình tính toán và float chiếm ít không gian hơn nhưng kém chính xác hơn.


1

Theo tiêu chuẩn của IEEE, float là biểu diễn 32 bit của một số thực trong khi double là đại diện 64 bit.

Trong các chương trình Java, chúng ta thường thấy việc sử dụng kiểu dữ liệu kép. Chỉ để tránh tràn vì phạm vi số có thể được cung cấp bằng cách sử dụng loại dữ liệu kép sẽ nhiều hơn phạm vi khi sử dụng float.

Ngoài ra khi cần độ chính xác cao, việc sử dụng gấp đôi được khuyến khích. Rất ít phương thức thư viện đã được triển khai từ lâu vẫn yêu cầu sử dụng kiểu dữ liệu float là điều bắt buộc (đó chỉ là do nó được thực hiện bằng float, không có gì khác!).

Nhưng nếu bạn chắc chắn rằng chương trình của bạn yêu cầu số lượng nhỏ và việc tràn sẽ không xảy ra khi bạn sử dụng float, thì việc sử dụng float sẽ cải thiện phần lớn độ phức tạp không gian của bạn vì phao cần một nửa bộ nhớ theo yêu cầu gấp đôi.


0

Ví dụ này minh họa cách trích xuất dấu (bit ngoài cùng bên trái), số mũ (8 bit sau) và mantissa (23 bit ngoài cùng bên phải) từ một float trong Java.

int bits = Float.floatToIntBits(-0.005f);
int sign = bits >>> 31;
int exp = (bits >>> 23 & ((1 << 8) - 1)) - ((1 << 7) - 1);
int mantissa = bits & ((1 << 23) - 1);
System.out.println(sign + " " + exp + " " + mantissa + " " +
  Float.intBitsToFloat((sign << 31) | (exp + ((1 << 7) - 1)) << 23 | mantissa));

Cách tiếp cận tương tự có thể được sử dụng cho double (số mũ 11 bit và mantissa 52 bit).

long bits = Double.doubleToLongBits(-0.005);
long sign = bits >>> 63;
long exp = (bits >>> 52 & ((1 << 11) - 1)) - ((1 << 10) - 1);
long mantissa = bits & ((1L << 52) - 1);
System.out.println(sign + " " + exp + " " + mantissa + " " +
  Double.longBitsToDouble((sign << 63) | (exp + ((1 << 10) - 1)) << 52 | mantissa));

Tín dụng: http://sj.github.io/java-float/


0

Bạn nên sử dụng gấp đôi thay vì float để tính toán chính xác và float thay vì double khi sử dụng các phép tính kém chính xác hơn. Float chỉ chứa các số thập phân, nhưng gấp đôi chứa một số dấu phẩy động có độ chính xác kép của IEEE754, giúp dễ dàng chứa và tính toán các số chính xác hơn. Hi vọng điêu nay co ich.


0

Trong tính toán lập trình thông thường, chúng tôi không sử dụng float. Nếu chúng tôi đảm bảo rằng phạm vi kết quả nằm trong phạm vi của kiểu dữ liệu float thì chúng tôi có thể chọn loại dữ liệu float để lưu bộ nhớ. Nói chung, chúng tôi sử dụng gấp đôi vì hai lý do: -

  • Nếu chúng ta muốn sử dụng số dấu phẩy động làm kiểu dữ liệu float thì người gọi phương thức phải rõ ràng là hậu tố F hoặc f, bởi vì theo mặc định, mọi số dấu phẩy động được coi là gấp đôi. Nó làm tăng gánh nặng cho lập trình viên. Nếu chúng ta sử dụng số dấu phẩy động làm kiểu dữ liệu kép thì chúng ta không cần thêm bất kỳ hậu tố nào.
  • Float là kiểu dữ liệu có độ chính xác đơn có nghĩa là nó chiếm 4 byte. Do đó trong các tính toán lớn, chúng tôi sẽ không nhận được kết quả hoàn chỉnh. Nếu chúng ta chọn kiểu dữ liệu kép, nó chiếm 8 byte và chúng ta sẽ nhận được kết quả hoàn chỉnh.

Cả hai kiểu dữ liệu float và double được thiết kế đặc biệt cho các tính toán khoa học, trong đó các lỗi xấp xỉ có thể chấp nhận được. Nếu độ chính xác là mối quan tâm hàng đầu sau đó, thì nên sử dụng lớp BigDecimal thay vì kiểu dữ liệu float hoặc double. Nguồn: - Kiểu dữ liệu float và double trong Java

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.