Cấp độ tương đối lớn nhất mà tôi có thể sử dụng float là gì?


13

Giống như đã được chứng minh với các trò chơi như bao vây ngục tối và KSP, một mức độ đủ lớn sẽ bắt đầu có trục trặc vì cách hoạt động của điểm nổi. Bạn không thể thêm 1e-20 đến 1e20 mà không mất độ chính xác.

Nếu tôi chọn giới hạn kích thước của cấp độ của mình, làm cách nào để tính tốc độ tối thiểu mà đối tượng của tôi có thể di chuyển cho đến khi nó bắt đầu bị biến dạng?

Câu trả lời:


26

Một float 32 bit có mantissa 23 bit .

Điều đó có nghĩa là mỗi số được biểu thị bằng 1.xxx xxx xxx xxx xxx xxx xxx xx nhân với một số lũy thừa bằng 2, trong đó mỗi x là một chữ số nhị phân, bằng 0 hoặc 1. (Ngoại trừ các số không chuẩn hóa cực kỳ nhỏ hơn - chúng bắt đầu bằng 0. thay vì 1., nhưng tôi sẽ bỏ qua chúng cho những gì tiếp theo)2-126

Vì vậy, trong phạm vi từ 2 ( i + 1 ) , bạn có thể biểu thị bất kỳ số nào trong độ chính xác là ± 2 ( i - 24 )2Tôi2(Tôi+1)±2(Tôi-24)

Ví dụ: với i = 0, số nhỏ nhất trong phạm vi này là (2 ^ 0) * 1 = 1. Số nhỏ nhất tiếp theo là (2 ^ 0) * (1 + 2 ^ -23). Nếu bạn muốn đại diện cho 1 + 2 ^ -24, bạn sẽ phải làm tròn lên hoặc xuống, với lỗi 2 ^ -24 theo bất kỳ cách nào.

In this range:                You get accuracy within:
-----------------------------------------------
         0.25   -     0.5    2^-26 = 1.490 116 119 384 77 E-08
         0.5    -     1      2^-25 = 2.980 232 238 769 53 E-08
         1     -      2      2^-24 = 5.960 464 477 539 06 E-08
         2     -      4      2^-23 = 1.192 092 895 507 81 E-07
         4     -      8      2^-22 = 2.384 185 791 015 62 E-07
         8     -     16      2^-21 = 4.768 371 582 031 25 E-07
        16     -     32      2^-20 = 9.536 743 164 062 5  E-07
        32     -     64      2^-19 = 1.907 348 632 812 5  E-06
        64     -    128      2^-18 = 0.000 003 814 697 265 625
       128    -     256      2^-17 = 0.000 007 629 394 531 25
       256    -     512      2^-16 = 0.000 015 258 789 062 5
       512    -   1 024      2^-15 = 0.000 030 517 578 125
     1 024    -   2 048      2^-14 = 0.000 061 035 156 25
     2 048    -   4 096      2^-13 = 0.000 122 070 312 5
     4 096    -   8 192      2^-12 = 0.000 244 140 625
     8 192   -   16 384      2^-11 = 0.000 488 281 25
    16 384   -   32 768      2^-10 = 0.000 976 562 5
    32 768   -   65 536      2^-9  = 0.001 953 125
    65 536   -  131 072      2^-8  = 0.003 906 25
   131 072   -  262 144      2^-7  = 0.007 812 5
   262 144   -  524 288      2^-6  = 0.015 625
   524 288 -  1 048 576      2^-5  = 0.031 25
 1 048 576 -  2 097 152      2^-4  = 0.062 5
 2 097 152 -  4 194 304      2^-3  = 0.125
 4 194 304 -  8 388 608      2^-2  = 0.25
 8 388 608 - 16 777 216      2^-1  = 0.5
16 777 216 - 33 554 432      2^0   = 1

Vì vậy, nếu đơn vị của bạn là mét, bạn sẽ mất độ chính xác đến từng milimet trong dải 16 484 - 32 768 (cách gốc khoảng 16-33 km).

Người ta thường tin rằng bạn có thể giải quyết vấn đề này bằng cách sử dụng một đơn vị cơ sở khác, nhưng điều đó không thực sự đúng, vì độ chính xác tương đối mới là vấn đề.

  • Nếu chúng tôi sử dụng centimet làm đơn vị của mình, chúng tôi sẽ mất độ chính xác đến milimet ở dải 1 048 576-2 097 152 (cách gốc 10-21 km)

  • Nếu chúng tôi sử dụng haametres làm đơn vị của mình, chúng tôi sẽ mất độ chính xác đến từng milimet ở dải 128-256 (cách gốc 13-26 km)

... Vì vậy, việc thay đổi đơn vị trên bốn bậc độ lớn vẫn kết thúc với sự mất độ chính xác đến từng milimet ở đâu đó trong phạm vi hàng chục km. Tất cả chúng ta đang dịch chuyển là nơi chính xác trong dải đó nó chạm (do sự không khớp giữa đánh số cơ sở 10 và cơ sở 2) không mở rộng đáng kể khu vực có thể chơi của chúng tôi.

Chính xác mức độ thiếu chính xác mà trò chơi của bạn có thể chịu đựng sẽ phụ thuộc vào chi tiết về lối chơi, mô phỏng vật lý, kích thước thực thể / khoảng cách vẽ, độ phân giải kết xuất, v.v ... vì vậy thật khó để đặt ra một điểm cắt chính xác. Nó có thể là kết xuất của bạn trông ổn từ nguồn gốc 50 km, nhưng đạn của bạn đang dịch chuyển qua các bức tường, hoặc một kịch bản trò chơi nhạy cảm đi haywire. Hoặc bạn có thể thấy trò chơi chơi tốt, nhưng mọi thứ đều có độ rung hầu như không nhận thấy được từ sự không chính xác trong biến đổi máy ảnh.

Nếu bạn biết mức độ chính xác mà bạn cần (giả sử, khoảng 0,01 đơn vị ánh xạ tới khoảng 1 px ở khoảng cách xem / tương tác thông thường của bạn và bất kỳ khoảng bù nhỏ hơn nào là vô hình), bạn có thể sử dụng bảng ở trên để tìm nơi bạn mất độ chính xác và lùi lại một vài đơn đặt hàng lớn để đảm bảo an toàn trong trường hợp hoạt động thua lỗ.

Nhưng nếu bạn đang nghĩ về khoảng cách rất lớn, có lẽ tốt hơn là bỏ qua tất cả những điều này bằng cách lấy lại thế giới của bạn khi người chơi di chuyển xung quanh. Bạn chọn một khu vực hình vuông hoặc khối lập phương nhỏ xung quanh gốc. Bất cứ khi nào người chơi di chuyển ra ngoài khu vực này, hãy dịch chúng và mọi thứ trên thế giới, lùi lại một nửa chiều rộng của khu vực này, giữ người chơi ở bên trong. Vì mọi thứ di chuyển cùng nhau, người chơi của bạn sẽ không thấy sự thay đổi. Sự không chính xác vẫn có thể xảy ra ở những nơi xa xôi trên thế giới, nhưng nhìn chung chúng ít được chú ý ở đó hơn là xảy ra ngay dưới chân bạn, và bạn được đảm bảo luôn có độ chính xác cao gần người chơi.


1
Recentering chắc chắn là con đường để đi!
Floris

2
Điều gì về việc sử dụng tọa độ điểm cố định? Có thể với số nguyên 64 bit nếu cần thiết?
API-Beast

Câu hỏi là, khu vực trung tâm lại có thể lớn đến mức nào? Ví dụ, trong trò chơi của tôi, tôi muốn chụp ở khoảng cách xa với zoom mạnh, tôi hoàn toàn cần phải sử dụng gấp đôi hay là đủ nổi? không phải là tốt hơn để recenter theo một cây quad hoặc một số thuật toán gạch?
jokoon

Nó sẽ phụ thuộc vào độ ổn định số của các thuật toán được sử dụng bởi các hệ thống kết xuất và vật lý của bạn - vì vậy đối với một cơ sở mã / động cơ nhất định, cách duy nhất để biết chắc chắn là thử một cảnh thử nghiệm. Chúng ta có thể sử dụng bảng để ước tính độ chính xác tối đa (ví dụ: Máy ảnh cách đối tượng 16 km sẽ có xu hướng nhìn thấy các lỗi có kích thước tối thiểu milimet, do đó, zoom của bạn phải đủ rộng để giữ những ảnh nhỏ hơn pixel - nếu nhu cầu thu phóng để chặt chẽ hơn cho trò chơi của bạn sau đó tăng gấp đôi hoặc một số phép toán thông minh có thể được yêu cầu), nhưng một chuỗi các hoạt động thua lỗ có thể gặp vấn đề tốt trước giới hạn giả định này.
DMGregory

Tôi vẫn đang tự hỏi nó có nghĩa gì khi lấy lại thế giới cho một API đồ họa. Nếu tôi có một khối lớn của hình học bản năng (hoặc không bản năng), nó vẫn an toàn để làm điều đó? Tôi đoán nó có nghĩa là dịch TẤT CẢ các biến đổi, nhưng nếu tôi làm điều này nhiều lần, liệu có nguy cơ mất độ chính xác của dấu phẩy động không?
jokoon

3

Thật khó để trả lời vì nó phụ thuộc vào quy mô vật lý của bạn: Tốc độ di chuyển tối thiểu chấp nhận được mà KHÔNG cần làm tròn thành 0 là bao nhiêu?

Nếu bạn cần một thế giới rộng lớn và vật lý nhất quán, tốt hơn là sử dụng một lớp điểm cố định.

Ví dụ, bắn một quả đạn pháo từ bất cứ nơi nào trên thế giới sẽ cho bạn kết quả tương tự và điểm cố định 64 bit (32,32) mang lại cho bạn một độ chính xác rất lớn và hơn bất kỳ thứ gì có thể nhận thấy trong hầu hết các trò chơi. Nếu đơn vị của bạn là 1 mét, bạn vẫn ở độ chính xác 232 picomet 214748 km so với gốc.

Bạn vẫn có thể thực hiện vật lý cục bộ tại các điểm nổi trong ô cục bộ để tiết kiệm công việc lập trình và sử dụng công cụ vật lý ngoài luồng. Nó vẫn sẽ phù hợp một cách hợp lý cho tất cả các mục đích thực tế.

Vì giai đoạn tiền thưởng rộng và AABB có xu hướng nhanh hơn ở điểm cố định do độ trễ của FPU. Cũng nhanh hơn để chuyển đổi một điểm cố định thành chỉ số octree (hoặc quadtree) vì bạn có thể thực hiện mặt nạ bit đơn giản.

Các hoạt động đó không được hưởng lợi nhiều từ các hướng dẫn và đường ống SIMD thường che giấu độ trễ của FPU.

Bạn có thể chuyển đổi vị trí thành điểm nổi SAU trừ vị trí của máy ảnh ở điểm cố định để hiển thị mọi thứ, tránh các vấn đề về điểm nổi trong một thế giới rộng lớn và vẫn sử dụng trình kết xuất thông thường sử dụng các điểm nổi.


-2

Bạn có thể tránh nó hoàn toàn bằng cách nhân.
Thay vì làm việc với phao, chỉ cần nhân chúng với 10 ^ (x), lưu trữ chúng và khi cần nhân lại với 10 ^ (- x).
Từ đó phụ thuộc vào loại int bạn muốn sử dụng.


1
Điều này không tránh được vấn đề. Định dạng điểm cố định vẫn có độ chính xác và phạm vi hữu hạn - phạm vi càng lớn, độ chính xác càng thấp (dựa trên vị trí bạn đặt dấu thập phân cố định đó) - vì vậy quyết định "tôi có thể tạo mức nào lớn mà không có lỗi làm tròn có thể nhìn thấy" vẫn áp dụng.
DMGregory

3
Hơn nữa, cơ sở 10 không thực tế lắm. Các số điểm cố định hoạt động tốt hơn rất nhiều khi bạn chia số nguyên theo các bit (xem xét không dấu 26.6 - thành phần phân số là 6 bit thấp hơn ( 1.0 / 64.0 * x & 63) và phần tách rời chỉ đơn giản là x >> 6) . Điều đó đơn giản hơn nhiều để thực hiện hơn là nâng một thứ gì đó lên sức mạnh mười.
Andon M. Coleman
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.