JavaRush /Blog Java /Random-VI /Số thập phân lớn trong Java

Số thập phân lớn trong Java

Xuất bản trong nhóm
Xin chào! Trong bài giảng hôm nay chúng ta sẽ nói về số lượng lớn. Không, về những cái THỰC SỰ LỚN. Trước đây , chúng ta đã nhiều lần thấy một bảng gồm các phạm vi giá trị cho các kiểu dữ liệu nguyên thủy. Nó trông như thế này:
Kiểu nguyên thủy Kích thước trong bộ nhớ Phạm vi giá trị
byte 8 bit -128 đến 127
ngắn 16bit đến -32768 đến 32767
ký tự 16bit từ 0 đến 65536
int 32 bit từ -2147483648 đến 2147483647
dài 64 bit từ -9223372036854775808 đến 9223372036854775807
trôi nổi 32 bit từ (2 lũy thừa -149) đến ((2-2 lũy thừa -23)*2 lũy thừa 127)
gấp đôi 64 bit từ (-2 lũy thừa 63) đến ((2 lũy thừa 63) - 1)
boolean 8 (khi được sử dụng trong mảng), 32 (khi được sử dụng trong không phải mảng) đúng hay sai
Nếu chúng ta đang nói về số nguyên, loại dữ liệu có dung lượng lớn nhất là long và khi chúng ta đang nói về số dấu phẩy động, double . Nhưng điều gì sẽ xảy ra nếu số lượng chúng ta cần quá lớn đến nỗi nó thậm chí không vừa với long ? Phạm vi giá trị Long có thể khá lớn, nhưng vẫn bị giới hạn ở một kích thước nhất định - 64 bit. Chúng ta có thể nghĩ ra điều gì nếu Số Rất Lớn của chúng ta nặng 100 bit? May mắn thay, bạn không cần phải phát minh ra bất cứ điều gì. Trong Java, hai lớp đặc biệt đã được tạo cho những trường hợp như vậy - BigInteger (đối với số nguyên) và BigDecimal (đối với số dấu phẩy động). Tính năng của họ là gì? Trước hết, về mặt lý thuyết chúng không có kích thước tối đa. Về mặt lý thuyết là vì không có máy tính nào có bộ nhớ vô hạn. Và nếu bạn tạo một số trong chương trình lớn hơn kích thước bộ nhớ của máy tính thì tất nhiên chương trình sẽ không hoạt động. Nhưng những trường hợp như vậy khó có thể xảy ra. Vì vậy, chúng ta có thể nói rằng kích thước của các con số thực tế BigIntegerBigDecimalkhông giới hạn. Những lớp này được sử dụng để làm gì? Trước hết là đối với những phép tính có yêu cầu độ chính xác cực cao. Ví dụ, có những chương trình trong đó cuộc sống con người có thể phụ thuộc vào độ chính xác của các phép tính (phần mềm dành cho máy bay và tên lửa hoặc dành cho thiết bị y tế). Vì vậy, nếu ngay cả chữ số thập phân thứ 150 cũng đóng vai trò quan trọng thì BigDecimalđó là lựa chọn tốt nhất. Ngoài ra, những đồ vật này thường được sử dụng trong thế giới tài chính, nơi độ chính xác của các phép tính đến những giá trị nhỏ nhất cũng cực kỳ quan trọng. Làm thế nào để làm việc với các đồ vật BigIntegerBigDecimalđiều gì quan trọng cần nhớ về chúng? Đối tượng của các lớp này được tạo như thế này:
public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Truyền một chuỗi dưới dạng tham số chỉ là một trong các hàm tạo có thể có. Ở đây chúng tôi sử dụng chuỗi vì số của chúng tôi vượt quá giá trị tối đa longdoublebằng cách nào đó chúng tôi cần giải thích cho trình biên dịch chính xác số chúng tôi muốn nhận :) Chỉ cần chuyển số 1111111111111111111111111111111111 111111111111111111111111111111111111111111 cho người xây dựng 111111111111111111111111111111111111111111111111111111111111111111111 sẽ không hoạt động: Java sẽ cố gắng “khớp” số được truyền vào một trong các kiểu dữ liệu nguyên thủy, nhưng nó sẽ không khớp với bất kỳ kiểu dữ liệu nào trong số đó. Vì vậy, sử dụng một chuỗi để truyền số mong muốn là một lựa chọn tốt. Cả hai lớp đều có thể tự động trích xuất các giá trị số từ các chuỗi được truyền. Một điểm quan trọng khác cần nhớ khi làm việc với các lớp có số lượng lớn là đối tượng của chúng là bất biến ( Immutable) . Bạn đã làm quen với nguyên tắc bất biến thông qua ví dụ về lớp Stringvà lớp bao bọc dành cho kiểu nguyên thủy (Số nguyên, Dài và các lớp khác).
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Đầu ra của bảng điều khiển:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Con số của chúng tôi không thay đổi, như bạn mong đợi. Để phép cộng thành công, bạn phải tạo một đối tượng mới và gán kết quả của phép cộng cho nó.
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Đầu ra của bảng điều khiển:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Bây giờ mọi thứ đều hoạt động như bình thường :) Nhân tiện, bạn có nhận thấy thao tác cộng trông khác thường như thế nào không?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
Đây là một điểm quan trọng khác. Các lớp số lượng lớn không sử dụng toán tử +-*/ trong hoạt động của chúng mà thay vào đó cung cấp một tập hợp các phương thức. Chúng ta hãy xem những cái chính (như mọi khi, bạn có thể tìm thấy danh sách đầy đủ các phương thức trong tài liệu của Oracle: tại đâytại đây ).
  1. các phương pháp thực hiện các phép tính số học: add() , subtract(), multiply(), divide(). Được sử dụng cho các phép tính cộng, trừ, nhân và chia tương ứng.

  2. doubleValue(), intValue(), floatValue(), longValue()vân vân. - Dùng để chuyển đổi một số lớn sang kiểu nguyên thủy Java. Hãy cẩn thận khi sử dụng chúng và nhớ sự khác biệt về dung lượng!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }

    Đầu ra của bảng điều khiển:

    
    8198552921648689607
  3. min()max()- cho phép bạn tìm giá trị tối thiểu và tối đa của hai số lớn được truyền.
    Xin lưu ý: các phương thức không tĩnh!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }

    Đầu ra của bảng điều khiển:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

Kiểm soát làm tròn số thập phân lớn

Chủ đề này được đưa vào một phần riêng, vì việc làm tròn số lớn và điều chỉnh nó không phải là việc đơn giản. Bạn có thể đặt số vị trí thập phân cho một số BigDecimalbằng cách sử dụng hàm setScale(). Ví dụ: chúng tôi muốn đặt độ chính xác của số 111.5555555555 thành ba chữ số thập phân. Tuy nhiên, chúng ta sẽ không thể chuyển số 3 làm đối số cho phương thức setScale()và do đó giải quyết được vấn đề của mình. Như đã đề cập ở trên, BigDecimalđây là những con số để tính toán với độ chính xác cao hơn. Ở dạng hiện tại, số của chúng tôi có 10 chữ số thập phân. Chúng ta muốn loại bỏ 7 trong số đó và chỉ để lại 3. Vì vậy, ngoài số 3, chúng ta phải chuyển chế độ làm tròn làm tham số . Tổng cộng có 8 chế độ làm tròn BigDecimal. Khá nhiều! Nhưng nếu bạn cần thực sự tinh chỉnh độ chính xác của các phép tính trong chương trình, bạn sẽ có mọi thứ bạn cần cho việc này. Vì vậy, đây là 8 chế độ làm tròn có sẵn trong BigDecimal:
  1. ROUND_CEILING- tập trung

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN- thải bỏ

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR- làm tròn xuống

    111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555

  4. ROUND_HALF_UP— làm tròn lên nếu số sau dấu thập phân >= .5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN— làm tròn lên nếu số sau dấu thập phân > 0,5

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN— làm tròn sẽ phụ thuộc vào số ở bên trái dấu thập phân. Nếu số bên trái là số chẵn thì làm tròn xuống. Nếu số ở bên trái dấu thập phân là số lẻ thì sẽ được làm tròn lên.

    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2

    Số ở bên trái dấu thập phân - 2 - là số chẵn. Làm tròn xảy ra xuống. Vì chúng tôi yêu cầu 0 chữ số thập phân nên kết quả sẽ là 2.

    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4

    Số ở bên trái dấu thập phân - 3 - là số lẻ. Làm tròn xảy ra hướng lên trên. Vì chúng tôi yêu cầu 0 chữ số thập phân nên kết quả sẽ là 4.

  7. ROUND_UNNECCESSARY— được sử dụng trong trường hợp chế độ làm tròn cần được chuyển sang một số phương thức, nhưng số không cần phải làm tròn. Nếu bạn cố gắng làm tròn một số khi chế độ ROUND_UNNECCESSARY được đặt, ArithmeticException sẽ bị ném ra.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP- tập trung.

    111.5551 -> setScale(3, ROUND_UP) -> 111.556

So sánh số lượng lớn

Câu hỏi này cũng quan trọng. Bạn đã nhớ rằng phương thức này được sử dụng để so sánh các đối tượng trong Java equals(). Nó được cung cấp bởi chính ngôn ngữ (trong trường hợp các lớp dựng sẵn của Java) hoặc bị lập trình viên ghi đè. Nhưng trong trường hợp đối tượng lớp, không nên BigDecimalsử dụng phương thức equals()để so sánh. Lý do cho điều này là BigDecimal.equals()phương thức hai số chỉ trả về true nếu hai số có cùng giá trị và tỷ lệ : Hãy so sánh hành vi của phương thức equals()y Doublevà y BigDecimal:
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));

   }
}
Đầu ra của bảng điều khiển:

true
false
Như bạn có thể thấy, các số 1,5 và 1,50 trong trường hợp c BigDecimalhóa ra không bằng nhau! Điều này xảy ra chính xác là do đặc thù của phương thức equals()trong lớp BigDecimal. Để so sánh chính xác hơn cả hai, BigDecimaltốt hơn nên sử dụng phương pháp compareTo():
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Đầu ra của bảng điều khiển:

0
Phương thức compareTo()trả về 0, nghĩa là bằng 1,5 và 1,50. Đây là kết quả mà chúng tôi đã trông đợi! :) Đến đây là bài học hôm nay của chúng ta đã kết thúc. Đã đến lúc quay lại với nhiệm vụ! :)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION