2009-08-07 42 views
19

Tôi đang tính toán khoa học có độ chính xác cao. Trong tìm kiếm đại diện tốt nhất của các hiệu ứng khác nhau, tôi tiếp tục đưa ra lý do để muốn có được số chính xác gấp đôi (hoặc thấp hơn) tiếp theo có sẵn. Về cơ bản, những gì tôi muốn làm là thêm một ít bit quan trọng nhất trong biểu diễn bên trong của một đôi.Số chính xác cao hơn/thấp hơn của IEEE

Khó khăn là định dạng IEEE không hoàn toàn đồng bộ. Nếu một người sử dụng mã cấp thấp và thực sự thêm một mã vào bit ít quan trọng nhất, định dạng kết quả có thể không phải là số có sẵn gấp đôi tiếp theo. Nó có thể, ví dụ, là một số trường hợp đặc biệt như PositiveInfinity hoặc NaN. Ngoài ra còn có các giá trị bình thường, mà tôi không yêu cầu để hiểu, nhưng dường như có các mẫu bit cụ thể khác với mẫu "bình thường".

Giá trị "epsilon" có sẵn, nhưng tôi chưa bao giờ hiểu định nghĩa của nó. Vì các giá trị kép không được đặt cách nhau đồng đều, không có giá trị đơn lẻ nào có thể được thêm vào giá trị gấp đôi để dẫn đến giá trị cao hơn tiếp theo.

Tôi thực sự không hiểu tại sao IEEE không chỉ định một hàm để nhận giá trị cao hơn hoặc cao hơn tiếp theo. Tôi không thể là người duy nhất cần nó.

Có cách nào để nhận giá trị tiếp theo không (không có loại vòng lặp cố gắng thêm giá trị nhỏ hơn và nhỏ hơn).

+2

IEEE-754 * có * đã chỉ định các chức năng như vậy - 'nextUp' và' nextDown' như được yêu cầu trong phần 5.3.1 của tiêu chuẩn sửa đổi (2008) và chức năng 'nextafter' được đề xuất ban đầu (1985) tiêu chuẩn và được yêu cầu trong C99. –

Trả lời

1

Tôi không chắc rằng tôi đang theo dõi sự cố của bạn. Chắc chắn tiêu chuẩn IEEE hoàn toàn đồng bộ? Ví dụ, hãy xem đoạn trích này từ số wikipedia article để biết số chính xác gấp đôi.

3ff0 0000 0000 0000 = 1 
3ff0 0000 0000 0001 = 1.0000000000000002, the next higher number > 1 
3ff0 0000 0000 0002 = 1.0000000000000004 

Có gì sai khi chỉ tăng bit ít quan trọng nhất, trong biểu diễn nhị phân hoặc hex?

Theo như các số đặc biệt đi (vô cùng, NaN, v.v.), chúng được xác định rõ và không có nhiều trong số chúng. Các giới hạn được xác định tương tự.

Vì bạn rõ ràng đã xem xét điều này, tôi hy vọng tôi đã có kết thúc sai của thanh. Nếu điều này không đủ cho vấn đề của bạn, bạn có thể thử và làm rõ những gì bạn muốn đạt được không? Mục tiêu của bạn ở đây là gì?

+0

Điều đó có hiệu quả trong trường hợp số mũ phải tăng lên không? –

+0

Mục đích của tôi là làm điều này một cách rõ ràng, tốt nhất là từ C#, nhưng tôi sẽ stoop đến mức bit nếu tôi phải. Vấn đề là tiêu chuẩn IEEE không thuộc phạm vi công cộng, và tôi không thể mua nó. Tiêu chuẩn xác định các mẫu bit cho trường hợp bạn hiển thị, nhưng cũng cho tất cả các số bất thường (chẳng hạn như các tiểu chuẩn). Người ta không cần phải biết đầy đủ chi tiết của tất cả các định dạng số để thực hiện tác vụ này. Nhưng nếu bạn lật bit mình, bạn sẽ phải. Điều gì sẽ xảy ra nếu số 'tiếp theo' là một thông thường? Trừ khi bạn biết tất cả các quy tắc, bạn KHÔNG THỂ đến đó! –

+1

@Mark T: Ok, tôi hiểu vấn đề của bạn ngay bây giờ. Tôi đã không nhận ra tiêu chuẩn không có sẵn tự do (tuyệt vời)! Dưới đây là các hiện thực của một số hàm, bao gồm dnxtaft.f, trả về giá trị dấu chấm động tiếp theo theo hướng x. Có lẽ điều này sẽ giúp? http://www.math.utah.edu/~beebe/software/ieee/ –

12

Có sẵn các chức năng để thực hiện chính xác điều đó, nhưng chúng có thể phụ thuộc vào ngôn ngữ bạn sử dụng. Hai ví dụ:

  • nếu bạn có quyền truy cập vào một thư viện toán học C99 phong nha, bạn có thể sử dụng nextafter (và phao của nó và các biến thể đôi dài, nextafterfnextafterl); hoặc gia đình nexttoward (mất gấp đôi đối số thứ hai).

  • nếu bạn viết Fortran, bạn có nearest nội tại sẵn

Nếu bạn không thể truy cập trực tiếp từ những ngôn ngữ của bạn, bạn cũng có thể nhìn vào cách họ đang thực hiện trong tự do có sẵn, chẳng hạn là this one.

2

Có, có một cách. Trong C#:

 public static double getInc (double d) 
     { 
       // Check for special values 
       if (double.IsPositiveInfinity(d) || double.IsNegativeInfinity(d)) 
        return d; 
       if (double.IsNaN(d)) 
        return d; 

       // Translate the double into binary representation 
       ulong bits = (ulong)BitConverter.DoubleToInt64Bits(d); 
       // Mask out the mantissa bits 
       bits &= 0xfff0000000000000L; 
       // Reduce exponent by 52 bits, so subtract 52 from the mantissa. 
       // First check if number is great enough. 
       ulong testWithoutSign = bits & 0x7ff0000000000000L; 
       if (testWithoutSign > 0x0350000000000000L) 
        bits -= 0x0350000000000000L; 
       else 
        bits = 0x0000000000000001L; 
       return BitConverter.Int64BitsToDouble((long)bits); 
} 

Mức tăng có thể được cộng và trừ.

+0

Điều này doesn ' t biên dịch, và tôi không nghĩ rằng bạn đang sử dụng đúng cách 'BitConverter.DoubleToInt64Bits' phương pháp anyway. Nếu bạn muốn nhận được biểu diễn byte của một số, bạn nên sử dụng 'BitConverter.GetBytes' (nhưng sau đó bạn cần đảm bảo rằng bạn tăng hoặc giảm số mũ, nếu cần). –

+0

Nó không biên dịch vì C# không cho phép kết hợp các hằng số và biến dài ulong/dài (điều này là ngu ngốc đối với các toán tử bit). Và bạn đã nghĩ sai, phương pháp BitConverter thực sự trả về cấu trúc byte bên trong của đôi ở định dạng IEEE. –

5

Như Thorsten S. nói, điều này có thể được thực hiện với lớp BitConverter, nhưng phương pháp của ông giả định rằng phương thức DoubleToInt64Bits trả về cấu trúc byte nội bộ của double, mà nó không. Số nguyên được trả về bởi phương thức đó thực sự trả về số lượng các cặp đôi có thể biểu diễn giữa 0 và của bạn. I E. nhỏ nhất tích cực đôi được đại diện bởi 1, đôi lớn nhất tiếp theo là 2, vv vv số âm bắt đầu tại long.MinValue và biến mất khỏi 0d.

Vì vậy, bạn có thể làm một cái gì đó như thế này:

public static double NextDouble(double value) { 

    // Get the long representation of value: 
    var longRep = BitConverter.DoubleToInt64Bits(value); 

    long nextLong; 
    if (longRep >= 0) // number is positive, so increment to go "up" 
     nextLong = longRep + 1L; 
    else if (longRep == long.MinValue) // number is -0 
     nextLong = 1L; 
    else // number is negative, so decrement to go "up" 
     nextLong = longRep - 1L; 

    return BitConverter.Int64BitsToDouble(nextLong); 
} 

này không đối phó với InfinityNaN, nhưng bạn có thể kiểm tra đối với những người và đối phó với họ tuy nhiên bạn thích, nếu bạn đang lo lắng về nó.

+0

Tôi thấy rằng bạn đang sử dụng mã của tôi vì đối số là giá trị, nhưng BitConverter.DoubleToInt64Bits nhận "d" làm đối số. Tôi đã đặt trước chỉ đơn giản là thêm một vì định dạng IEEE tách biệt số mũ và độ khó, nhưng vì nó có một bit ẩn , chức năng của bạn thực tế là ok như tôi thấy. –

6

Hầu hết các ngôn ngữ có chức năng nội tại hoặc thư viện để có được số chính xác đơn (32 bit) và/hoặc độ chính xác kép (64 bit) tiếp theo hoặc trước đó.

Đối với người dùng số học dấu chấm động 32 bit và 64 bit, sự hiểu biết về cấu trúc cơ bản rất hữu ích để tránh một số mối nguy hiểm với chúng. Tiêu chuẩn IEEE áp dụng thống nhất, nhưng vẫn để lại một số chi tiết cho người thực hiện. Do đó, một giải pháp phổ quát nền tảng dựa trên thao tác bit của các biểu diễn từ máy có thể có vấn đề và có thể phụ thuộc vào các vấn đề như endian và vân vân. Trong khi hiểu rõ tất cả các chi tiết đẫm máu về mức độ có thể hoặc sẽ hoạt động ở mức bit có thể chứng minh sức mạnh trí tuệ, thì tốt hơn nên sử dụng giải pháp nội tại hoặc thư viện được thiết kế riêng cho từng nền tảng và có API chung trên các nền tảng được hỗ trợ.

Tôi đã nhận thấy các giải pháp cho C# và C++. Dưới đây là một số cho Java:

Math.nextUp:

public static double NextUp (double d):

  • Trả về giá trị dấu chấm động tiếp giáp với d theo hướng vô cùng tích cực. Phương pháp này tương đương về mặt ngữ nghĩa với nextAfter (d, Double.POSITIVE_INFINITY); tuy nhiên, việc triển khai tiếp theo có thể chạy nhanh hơn lệnh gọi tiếp theo sau đó.

Các trường hợp đặc biệt:

  • Nếu đối số là NaN, kết quả là NaN.
  • Nếu đối số là vô cực dương, kết quả là dương vô cùng.
  • Nếu đối số là số không, kết quả là Double.MIN_VALUE

Tham số:

  • d - bắt đầu dấu chấm động giá trị

Returns:

  • Giá trị dấu phẩy động liền kề gần với cực dương.

công phao tĩnh NextUp (float f):

  • Trả về giá trị dấu chấm động tiếp giáp với f theo hướng dương vô cực. Phương pháp này tương đương ngữ nghĩa với nextAfter (f, Float.POSITIVE_INFINITY); tuy nhiên, việc triển khai tiếp theo có thể chạy nhanh hơn lệnh gọi tiếp theo sau đó.

Các trường hợp đặc biệt:

  • Nếu đối số là NaN, kết quả là NaN.
  • Nếu đối số là vô cực dương, kết quả là dương vô cùng.
  • Nếu đối số là số không, kết quả là Float.MIN_VALUE

Tham số:

  • f - bắt đầu từ dấu chấm động giá trị

Returns:

  • Giá trị dấu phẩy động liền kề gần với cực dương.

Hai loại tiếp theo phức tạp hơn một chút để sử dụng. Tuy nhiên, một hướng về không hoặc hướng tới một trong hai cực dương hoặc âm có vẻ là sử dụng hữu ích và có khả năng hơn. Một cách sử dụng khác là xem một giá trị trung gian tồn tại giữa hai giá trị. Người ta có thể xác định có bao nhiêu tồn tại giữa hai giá trị với một vòng lặp và truy cập. Ngoài ra, có vẻ như chúng, cùng với các phương pháp nextUp, có thể hữu ích cho việc tăng/giảm cho các vòng lặp.

Math.nextAfter:

public static double nextAfter (bắt đầu tăng gấp đôi, hướng đôi)

  • Trả về số dấu chấm động tiếp giáp với đối số đầu tiên trong sự chỉ đạo của đối số thứ hai. Nếu cả hai đối số so sánh là bằng đối số thứ hai được trả về.

Trường hợp đặc biệt:

  • Nếu một trong hai đối số là một NaN, sau đó NaN được trả về.
  • Nếu cả hai đối số đều được ký 0, hướng được trả về không thay đổi (như ngụ ý bởi yêu cầu trả về đối số thứ hai nếu đối số so sánh bằng nhau).
  • Nếu bắt đầu là ± Double.MIN_VALUE và hướng có giá trị sao cho kết quả phải có độ lớn nhỏ hơn, sau đó một số không có cùng ký hiệu khi bắt đầu được trả về.
  • Nếu bắt đầu là vô hạn và hướng có giá trị sao cho kết quả phải có độ lớn nhỏ hơn, gấp đôi .MAX_VALUE với cùng một dấu hiệu khi bắt đầu được trả về.
  • Nếu bắt đầu bằng ± Double.MAX_VALUE và hướng có giá trị sao cho kết quả phải có độ lớn hơn, vô cùng với cùng một dấu khi bắt đầu được trả về.

Tham số:

  • bắt đầu - bắt đầu từ giá trị dấu chấm động
  • hướng - Giá trị chỉ ra mà hàng xóm bắt đầu hoặc bắt đầu nên được trả lại

Returns:

  • Dấu phẩy động số liền kề để bắt đầu theo hướng của hướng.

public static (bắt đầu float, hướng kép) float nextAfter

  • Trả về số dấu chấm động tiếp giáp với đối số đầu tiên trong sự chỉ đạo của đối số thứ hai. Nếu cả hai đối số so sánh là bằng một giá trị tương đương với đối số thứ hai được trả về.

Trường hợp đặc biệt:

  • Nếu một trong hai đối số là một NaN, sau đó NaN được trả về.
  • Nếu cả hai đối số là số 0 đã ký, giá trị tương đương với hướng được trả về.
  • Nếu bắt đầu là ± Float.MIN_VALUE và hướng có giá trị sao cho kết quả phải có độ lớn nhỏ hơn, thì số không với cùng một dấu hiệu khi bắt đầu được trả về.
  • Nếu bắt đầu là vô hạn và hướng có giá trị sao cho kết quả phải có độ lớn nhỏ hơn, Float.MAX_VALUE với cùng một dấu hiệu khi bắt đầu được trả về.
  • Nếu bắt đầu bằng ± Float.MAX_VALUE và hướng có giá trị kết quả phải có độ lớn hơn, vô cùng với cùng một dấu hiệu khi bắt đầu được trả về.

Tham số:

  • bắt đầu - bắt đầu từ giá trị dấu chấm động
  • hướng - Giá trị chỉ ra mà hàng xóm bắt đầu hoặc bắt đầu nên được trả lại

Returns:

  • Số dấu chấm động liền kề để bắt đầu trong hướng của hướng.
1

Về hàm epsilon, đó là ước tính khoảng cách gần đúng của giá trị thập phân mà giá trị nhị phân đôi có thể là. Đó là vì, đối với các số thập phân dương hoặc âm cực lớn hoặc số thập phân dương hoặc âm rất nhỏ, nhiều trong số chúng ánh xạ tới cùng một biểu diễn nhị phân dưới dạng số kép. Hãy thử một số số thập phân rất, rất lớn hoặc rất, rất nhỏ, tạo số nhân đôi từ chúng và sau đó chuyển trở lại số thập phân. Bạn sẽ thấy rằng bạn sẽ không nhận được cùng một số thập phân trở lại, nhưng một trong đó là đôi gần nhất để thay thế.

Đối với các giá trị gần (gần tương đối với phạm vi rộng lớn các giá trị thập phân đôi có thể đại diện) 1 hoặc -1, epsilon sẽ bằng 0 hoặc rất, rất nhỏ. Đối với các giá trị dần dần tiến tới + hoặc - vô cùng hoặc không, epsilon sẽ bắt đầu phát triển. Tại các giá trị cực gần bằng 0 hoặc vô cùng, epsilon sẽ rất lớn vì các biểu diễn nhị phân có sẵn cho các giá trị thập phân trong các phạm vi đó rất, rất thưa thớt.

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