Tính toán kinh độ chính xác khi nó kết thúc | 180 |?


11

Tôi đang cố gắng phát triển một "công thức" để sửa các giá trị lat-lng.

Tôi đang sử dụng tờ rơi vue nhưng khi bạn ra ngoài thế giới "đầu tiên", bạn sẽ nhận được số lượng lớn. Trên +180 hoặc dưới -180.

Ví dụ: khi tôi di chuyển sang Mỹ ở bên phải (hướng đông), tôi nhận được là lng 215. Trong tâm trí của tôi, tôi sẽ chỉ sửa nó với 215-360=-145

Điều tương tự là khi tôi xoay sang phía đông nước Nga ở bên trái (hướng tây) và tôi lấy ví dụ-222. Bây giờ tôi cần tính toán-222+360=138

Tuy nhiên, vì thế giới là vô định, người dùng có thể chuyển sang thế giới thứ 8 và tôi phải điều chỉnh các giá trị.

Có thể tính toán kinh độ đúng không? (và một yêu cầu khác là khi người dùng ở thế giới thứ nhất, 24 lng vẫn phải là 24 lng.

Câu trả lời:


16

Bạn cần liên tục thêm (hoặc trừ) 360 vào giá trị của mình cho đến khi nó nằm trong phạm vi -180 - 180. Vì vậy, thường là một cặp vòng như:

lon = -187;
while(lon < -180){
  lon +=360;
}
while (lon > 180){
  lon -= 360;
}

Dấu hiệu sai đường vòng? Nên lon + = 360 trong trường hợp đầu tiên.
JimT

4
bạn chỉ có thể thực hiện nó với một vòng lặp while (Math.abs(lon) > 180) { lon -= Math.sign(lon) * 360 }Tôi không cung cấp câu trả lời vì phiên bản của bạn thực sự phù hợp với lời giải thích, trong khi phiên bản của tôi chỉ là một tối ưu hóa có khả năng không tạo ra bất kỳ sự khác biệt nào. Tôi giữ nó như một nhận xét chỉ như một lời nhắc nhở rằng mọi thứ có thể được thực hiện theo nhiều cách, một số tối ưu hơn so với những người khác.
Andrei

2
Tôi không nghĩ rằng tôi sẽ sử dụng cái đó vì nó sử dụng 2 lệnh gọi cho mỗi vòng lặp và chỉ một vòng lặp của tôi sẽ thực hiện. Có lẽ không có sự khác biệt trong ví dụ này nhưng đó là định kiến ​​của tôi
Ian Turton

trong khi chúng trông giống như các hàm, các hàm Math trong JavaScript nên được xem giống như các toán tử với các ký hiệu dài dòng. Theo nghĩa này, chúng ta cũng có thể thấy + - và thậm chí <là các hàm. Chỉnh sửa: Tôi đã có một giải pháp ở đây là nó không thực sự hoạt động
Andrei

2
Bạn không thể làm gì lon %= 180?
Vụ kiện của Quỹ Monica

15

Một câu trả lời tránh các điều kiện và chức năng gọi:

longitude = (longitude % 360 + 540) % 360 - 180

Tôi đã viết một microbenchmark nhanh tại https://jsperf.com/longitude-n normalisation và mã điều kiện dường như nhanh hơn (trong Chrome trên máy của tôi) cho các phạm vi giá trị đầu vào 'hợp lý'. Nói chung, có lẽ bạn không nên lo lắng về hiệu suất trong các tính toán nhỏ như thế này, mang lại nhiều trọng lượng hơn cho tính dễ đọc và tính nhất quán với phần còn lại của cơ sở mã của bạn.

Có lẽ quan trọng hơn trong trường hợp này là câu hỏi liệu mã của bạn có thể gặp các giá trị đầu vào cực đoan không (1e10, Infinity, v.v.). Nếu vậy, việc thực hiện lặp có thể sẽ chạy rất chậm hoặc âm thầm treo chương trình của bạn. Điều này có thể xảy ra với các tính toán được thực hiện gần các cực, ví dụ như cố gắng xoay hướng đông hoặc tây theo một khoảng cách (chứ không phải góc) từ một cực có thể dễ dàng dẫn đến một kinh độ vô hạn.


1
Hấp dẫn. Hãy đua một jmp có điều kiện chống lại sự phân chia FP. Hmmm tôi tự hỏi.
Joshua

1
@Joshua Bạn không thể sử dụng bước nhảy có điều kiện. Bạn phải sử dụng nhiều bước nhảy có điều kiện , còn gọi là vòng lặp. (Cộng với vòng lặp chứa điểm nổi bổ sung, không miễn phí.) Có bao nhiêu lần lặp mà vòng lặp cần phụ thuộc vào đầu vào. Vì vậy, bạn phải biết một cái gì đó về dữ liệu để xem hiệu suất. Nếu đại đa số ở gần phạm vi mong muốn và yêu cầu vài lần lặp, chắc chắn, vòng lặp bổ sung có thể nhanh hơn, nhưng nó không rõ ràng như lời châm biếm của bạn gợi ý.
jpmc26

1
@ jpmc26: Trong trường hợp này, việc mong đợi đi vòng quanh nhiều lần là điều ngớ ngẩn.
Joshua

1
Không có sự mỉa mai. Tôi thực sự không biết nó sẽ rơi theo cách nào.
Joshua

1
@Joshua yep, tôi cũng không chắc :). Tôi đã thêm nhiều hơn vào câu trả lời về hiệu suất (và trường hợp thất bại tiềm ẩn của mã vòng lặp)
Joe Lee-Moyet

5

Lót:

normalized = remainder(longitude, 360);

Giải thích: Bạn muốn biết những gì còn lại sau khi bạn bỏ qua các vòng quay đầy đủ (360 °).

Quá trình này được gọi là bình thường hóa.

Ví dụ (cpp.sh)


1
Điều này sẽ không dẫn đến giá trị [0, 360) chứ không phải [-180, 180] như Shadrix yêu cầu?
Chàng trai với chiếc mũ

@TheGuywithTheHat Kiểm tra ví dụ này: cpp.sh/7uy2v
Dựa trên

À, không biết đây là C ++. Trong ngữ cảnh JavaScript của Shadrix, tôi đã hiểu remaindermodulus. Mô-đun trong JS sẽ dẫn đến [0, 360).
Chàng trai với chiếc mũ

1
Tôi không nghĩ rằng nó sẽ làm việc. Bạn sẽ cần phải trừ đi kết quả 360 iff> 180. Một vấn đề khác tôi vừa nhận ra với JavaScript là modulo đối xứng qua 0, ví dụ -1 % 3là -1, chứ không phải 2 như nó cần thiết để nó hoạt động ở đây. remainderlà một giải pháp C ++ tuyệt vời, nhưng thật không may, không có hàm / toán tử nào trong JS đủ tương tự để có ích.
Chàng trai với chiếc mũ

0

Một lựa chọn khác: kinh độ = atan2 (cos (dài), sin (dài))


1
Đây dường như không phải là một ý tưởng tốt. Rất khó hiểu, tính toán tốn kém và có khả năng bị lỗi làm tròn.
David Richerby

0

Nếu ngôn ngữ lập trình bạn đang sử dụng hỗ trợ toán tử% (mod) trên các số dấu phẩy động (như Python và Ruby), tôi khuyên bạn nên sử dụng ngôn ngữ đó. Mặt khác, một số ngôn ngữ khác (như C và C ++) cho phép bạn sử dụng fmod ().

(Dù bạn sử dụng toán tử mod nào, hãy đảm bảo trước rằng nó sẽ thực hiện các thao tác mod trên các số dấu phẩy động và nó sẽ luôn cung cấp cho bạn các câu trả lời không âm. điểm lat / lon không đúng.)

Sử dụng nó như thế này:

# Put the longitude in the range of [0,360):
longitude %= 360

# Put the longitude in the range of [-180,180):
if longitude >= 180:
    longitude -= 360

Nếu bạn muốn làm tất cả trong một dòng:

# Put the longitude in the range of [-180,180):
longitude = (longitude + 180) % 360 - 180

Các phương pháp này không có vòng lặp, vì vậy chúng sẽ bình thường hóa các giá trị kinh độ mà không cần phải lặp lại cộng hoặc trừ, bất kể số lần quan sát của bạn đã xoay quanh trái đất bao nhiêu lần.

Biên tập:

Hmmm ... Tôi chỉ nhận thấy rằng Javascript dường như không xử lý %với các giá trị âm như tôi nghĩ nó sẽ xảy ra.

Trong trường hợp đó, hãy thử một lớp lót này:

longitude = (longitude + 36180) % 360 - 180

Các 36180chúng ta đang thêm là 36.000 + 180. Các 36.000 là để di chuyển một giá trị âm vào lĩnh vực tích cực, và 180 là để chuyển nó qua để khi nó được modded của 360, nó sẽ nằm trong khoảng [0360) . Phần này - 180chuyển nó trở lại phạm vi [-180,180).

Đây là một lớp lót khác, một lớp không dựa vào 36.000 là đủ lớn:

longitude = (longitude % 360 + 360 + 180) % 360 - 180

Phần longitude % 360 + 360này sẽ đảm bảo giá trị nằm trong miền dương khi được sửa đổi sau này 360. Bộ + 180phận này sẽ dịch chuyển nó để sau này bị trừ 180 (với - 180), nó sẽ nằm trong phạm vi mong muốn là [-180,180).


1
Lưu ý: C, C ++ fmod(longitude, 360)-> (-360.0 ... +360.0) và ilongitude % 360-> [-359 ... +359].
chux - Phục hồi Monica

@chux - Tôi không biết về điều đó, vì vậy tôi mới kiểm tra và có vẻ như bạn đã đúng. Cảm ơn bạn đã chỉ ra rằng.
JL
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.