2012-05-10 69 views
7

Tôi đã thử nghiệm với Python như một người nhận thức trong vài giờ qua. Tôi đã viết một hàm đệ quy, trả về recurse (x) là x! trong Python và trong Java, để so sánh hai. Hai đoạn mã giống hệt nhau, nhưng vì một lý do nào đó, mã Python hoạt động, trong khi mã Java thì không. Trong Python, tôi đã viết:Tại sao hai đoạn mã tương tự lại tạo ra các kết quả khác nhau?

x = int(raw_input("Enter: ")) 

def recurse(num): 
    if num != 0: 
     num = num * recurse(num-1) 
    else: 
     return 1 

    return num 

print recurse(x) 

đâu biến num sẽ nhân bản thân bằng cách num-1 cho đến khi nó đạt đến 0, và kết quả đầu ra kết quả. Trong Java, mã này là rất giống nhau, chỉ còn:

public class Default { 
    static Scanner input = new Scanner(System.in); 
    public static void main(String[] args){ 

      System.out.print("Enter: "); 
      int x = input.nextInt(); 
      System.out.print(recurse(x)); 


} 

    public static int recurse(int num){ 

    if(num != 0){ 
    num = num * recurse(num - 1); 
    } else { 
     return 1; 
    } 

    return num; 

} 

}

Nếu tôi nhập 25, Bộ luật Python trả 1.5511x10E25, đó là câu trả lời đúng, nhưng mã Java trả 2076180480, mà không phải là câu trả lời đúng, và tôi không chắc tại sao.

Cả hai mã đi về cùng quá trình:

  • Kiểm tra xem num là zero
  • Nếu num không phải là zero
    • num = num nhân với đệ quy của num - 1
  • Nếu số không là số
    • Trả lại 1, kết thúc chồng cuộc gọi recurse đó và c ausing mỗi num trở lại bắt đầu nhân
  • trở num

Không có dấu ngoặc trong python; Tôi nghĩ rằng bằng cách nào đó đã thay đổi mọi thứ, vì vậy tôi đã loại bỏ các dấu ngoặc đơn khỏi mã Java, nhưng nó không thay đổi. Thay đổi boolean (num! = 0) thành (num> 0) cũng không thay đổi gì cả. Thêm câu lệnh if vào ngữ cảnh được cung cấp khác, nhưng giá trị vẫn như cũ.

in các giá trị của num tại mọi điểm đưa ra một ý tưởng về cách các chức năng đi sai:

Python:

1 
2 
6 
24 
120 
720 
5040 
40320 
362880 
3628800 
39916800 
479001600 
6227020800 
87178291200 
1307674368000 
20922789888000 
355687428096000 
6402373705728000 
121645100408832000 
2432902008176640000 
51090942171709440000 
1124000727777607680000 
25852016738884976640000 
620448401733239439360000 
15511210043330985984000000 
15511210043330985984000000 

Một gia tăng ổn định. Trong Java:

1 
2 
6 
24 
120 
720 
5040 
40320 
362880 
3628800 
39916800 
479001600 
1932053504 
1278945280 
2004310016 
2004189184 
-288522240 
-898433024 
109641728 
-2102132736 
-1195114496 
-522715136 
862453760 
-775946240 
2076180480 
2076180480 

Không tăng đều đặn. Thực tế, num đang trả lại số số âm, như thể hàm trả về số âm, mặc dù num không được nhận dưới 0.

Cả mã Python và Java đều đang thực hiện cùng một quy trình, nhưng chúng đang trả lại các giá trị cực kỳ khác nhau. Tại sao chuyện này đang xảy ra?

+6

Số nguyên tràn ... – Mysticial

+3

Python quảng bá từ int đến dài tự động trong khi java thì không. – jamylak

+0

Đây là một câu hỏi hay ở chỗ đó là điều mà tất cả những người trả lời câu hỏi ở đây ngay lập tức hiểu được vấn đề, nhưng đó là điều bạn không thể tìm kiếm trừ khi bạn đã biết những gì mà vấn đề được gọi. –

Trả lời

11

Hai chữ - integer overflow

Trong khi không phải là một chuyên gia trong python, tôi giả sử nó có thể mở rộng kích thước của các loại nguyên theo nhu cầu của mình.

Trong Java, tuy nhiên, kích thước của loại int là cố định - 32 bit và do int được ký, chúng tôi thực sự chỉ có 31 bit để biểu thị số dương. Khi số bạn chỉ định lớn hơn số tối đa, nó sẽ tràn vào int (nghĩa là - không có chỗ nào đại diện cho toàn bộ số).

Trong khi ở ngôn ngữ C, hành vi trong trường hợp này không được xác định, trong Java nó được xác định rõ và chỉ mất ít nhất 4 byte kết quả.

Ví dụ:

System.out.println(Integer.MAX_VALUE + 1); 
// Integer.MAX_VALUE = 0x7fffffff 

kết quả trong:

-2147483648 
// 0x7fffffff + 1 = 0x800000000 

Sửa

Chỉ cần để làm cho nó rõ ràng hơn, đây là một ví dụ khác. Các mã sau đây:

int a = 0x12345678; 
int b = 0x12345678; 
System.out.println("a*b as int multiplication (overflown) [DECIMAL]: " + (a*b)); 
System.out.println("a*b as int multiplication (overflown) [HEX]: 0x" + Integer.toHexString(a*b)); 
System.out.println("a*b as long multiplication (overflown) [DECIMAL]: " + ((long)a*b)); 
System.out.println("a*b as long multiplication (overflown) [HEX]: 0x" + Long.toHexString((long)a*b)); 

kết quả đầu ra:

a*b as int multiplication (overflown) [DECIMAL]: 502585408 
a*b as int multiplication (overflown) [HEX]: 0x1df4d840 
a*b as long multiplication (overflown) [DECIMAL]: 93281312872650816 
a*b as long multiplication (overflown) [HEX]: 0x14b66dc1df4d840 

Và bạn có thể thấy rằng sản lượng thứ hai là ít nhất 4 byte của 4 đầu ra

+1

Thú vị. Bạn có thể cung cấp ngữ cảnh không? – Zolani13

+0

Nghiêm túc, OP tiểu bang s/anh ta là một người mới bắt đầu - cung cấp thêm một chút chi tiết ở đây. – kaveman

+1

@ Zolani13 - vui lòng xem chỉnh sửa. – MByD

2

Không giống như Java, Python đã xây dựng-in hỗ trợ cho long integers có độ chính xác không giới hạn. Trong Java, một số nguyên được giới hạn ở 32 bit và sẽ là overflow.

1

Như người khác đã viết, bạn bị tràn; các số đơn giản sẽ không khớp với biểu diễn dữ liệu của java. Python có một khả năng được xây dựng trong bignum như nơi java đã không.

Hãy thử một số giá trị nhỏ hơn và bạn sẽ thấy bạn mã java hoạt động tốt.

1

Java int phạm vi

int 4 byte, ký (hai của bổ sung). -2,147,483,648 đến 2,147,483,647. Giống như tất cả các kiểu số int có thể được đúc thành các kiểu số khác (byte, ngắn, dài, float, double). Khi phôi bị mất được thực hiện (ví dụ: int thành byte), việc chuyển đổi được thực hiện theo chiều dài của loại nhỏ hơn.

đây khoảng int bị hạn chế

0

Vấn đề là rất đơn giản ..
coz trong java giới hạn tối đa của số nguyên là 2147483647 u có thể in nó bằng cách System.out.println(Integer.MAX_VALUE); và tối thiểu là System.out.println(Integer.MIN_VALUE);

0

Vì trong phiên bản java bạn lưu trữ số như là một int mà tôi tin là 32-bit. Xem xét số lớn nhất (chưa ký) bạn có thể lưu trữ với hai bit trong nhị phân: 11 là số thứ ba trong số thập phân. Số lớn nhất có thể được lưu trữ bốn bit trong nhị phân là 1111, là số 15 trong số thập phân. Số 32 bit (đã ký) không thể lưu trữ bất kỳ thứ gì lớn hơn 2.147.483.647. Khi bạn cố gắng lưu trữ một số lớn hơn số này, nó đột nhiên kết thúc tốt đẹp trở lại và bắt đầu đếm từ các số âm. Điều này được gọi là tràn.

Nếu bạn muốn thử lưu trữ số lớn hơn, hãy thử dài.

Các vấn đề liên quan