2 कोणों के बीच सबसे छोटा अंतर


137

रेंज में 2 कोणों को देखते हुए -PI -> एक समन्वय के आसपास PI, उनके बीच के 2 कोणों में से सबसे छोटा मूल्य क्या है?

ध्यान में रखते हुए कि पीआई और पीआई के बीच का अंतर 2 पीआई नहीं है बल्कि शून्य है।

उदाहरण:

एक सर्कल की कल्पना करें, केंद्र से 2 रेखाएं निकलती हैं, उन रेखाओं के बीच 2 कोण हैं, जो कोण वे उर्फ छोटे कोण के अंदर बनाते हैं , और वे जिस कोण पर बाहर बनाते हैं, उर्फ ​​बड़ा कोण। जोड़े जाने पर दोनों कोण एक पूर्ण चक्र बनाते हैं। यह देखते हुए कि प्रत्येक कोण एक निश्चित सीमा के भीतर फिट हो सकता है , रोलओवर को ध्यान में रखते हुए, छोटे कोण मूल्य क्या है


2
आपके द्वारा समझे जाने से पहले मैंने 3 बार पढ़ा। कृपया एक उदाहरण जोड़ें, या बेहतर समझाएँ ...
कोबी

एक सर्कल की कल्पना करें, केंद्र से 2 रेखाएं निकलती हैं, उन रेखाओं के बीच 2 कोण होते हैं, जो कोण वे उर्फ ​​छोटे कोण के अंदर बनाते हैं, और वे जिस कोण से बाहर होते हैं, उर्फ ​​बड़ा कोण होता है। जोड़े जाने पर दोनों कोण एक पूर्ण चक्र बनाते हैं। यह देखते हुए कि प्रत्येक कोण एक निश्चित सीमा के भीतर फिट हो सकता है, छोटे कोणों का मूल्य क्या है, रोलओवर को ध्यान में रखते हुए
टॉम जे नोवेल


2
@JimG। यह एक ही सवाल नहीं है, इस सवाल में अन्य प्रश्न में इस्तेमाल किया गया कोण P1 गलत उत्तर होगा, यह दूसरा, छोटा कोण होगा। इसके अलावा, इस बात की कोई गारंटी नहीं है कि कोण क्षैतिज अक्ष के साथ है
टॉम जे नोवेल

जवाबों:


193

यह किसी भी कोण के लिए एक हस्ताक्षरित कोण देता है:

a = targetA - sourceA
a = (a + 180) % 360 - 180

कई भाषाओं में सावधान रहें कि moduloऑपरेशन उसी चिह्न के साथ एक मान देता है जैसे लाभांश (जैसे सी, सी ++, सी #, जावास्क्रिप्ट, पूरी सूची यहां )। इसके लिए कस्टम modफ़ंक्शन की आवश्यकता होती है :

mod = (a, n) -> a - floor(a/n) * n

या ऐसा:

mod = (a, n) -> (a % n + n) % n

यदि कोण [-180, 180] के भीतर हैं, तो यह भी काम करता है:

a = targetA - sourceA
a += (a>180) ? -360 : (a<-180) ? 360 : 0

अधिक क्रियात्मक तरीके से:

a = targetA - sourceA
a -= 360 if a > 180
a += 360 if a < -180

सरल और अधिक समझ में आता है ज़ोर से पढ़ा जाता है, हालांकि प्रभावी रूप से एक ही चीज़, पहले बीटीआई कोण से बाहर निकलता है, दूसरा भाग सुनिश्चित करता है कि यह हमेशा 2 संभव कोणों में से छोटा हो
टॉम जे नोवेल

1
हालाँकि एक व्यक्ति 360% करना चाहता है, उदाहरण के लिए यदि मेरे पास कोण 0 और लक्ष्य कोण 721 है, तो सही उत्तर 1 होगा, ऊपर दिया गया उत्तर 361 होगा
टॉम जे नोवेल

1
अधिक संक्षिप्त, हालांकि संभावित रूप से अधिक महंगा है, बाद के दृष्टिकोण के दूसरे कथन के बराबर है a -= 360*sgn(a)*(abs(a) > 180)। (यह सोचने के लिए आइए, अगर आपने शाखाविहीन कार्यान्वयन किया है sgnऔर abs, तो वह विशेषता वास्तव में कई गुणा आवश्यकता के लिए क्षतिपूर्ति करना शुरू कर सकती है।)
एमरिटेट

1
"किसी भी कोण के लिए हस्ताक्षरित कोण" उदाहरण एक अपवाद के साथ, अधिकांश परिदृश्यों में काम करने लगता है। परिदृश्य में double targetA = 2; double sourceA = 359;'a' 3.0 के बजाय -357.0 के बराबर होगा
Stevoisiak

3
C ++ में आप फ्लोटिंग पॉइंट मोडुलो का उपयोग करने के लिए std :: fmod (a, 360), या fmod (a, 360) का उपयोग कर सकते हैं।
जोप्पी

145

x लक्ष्य कोण है। y स्रोत या शुरुआती कोण है:

atan2(sin(x-y), cos(x-y))

यह हस्ताक्षरित डेल्टा कोण लौटाता है। ध्यान दें कि आपके API के आधार पर atan2 () फ़ंक्शन के मापदंडों का क्रम भिन्न हो सकता है।


13
x-yआपको कोण में अंतर देता है, लेकिन यह वांछित सीमा से बाहर हो सकता है। यूनिट सर्कल पर एक बिंदु को परिभाषित करने वाले इस कोण के बारे में सोचें। उस बिंदु के निर्देशांक हैं (cos(x-y), sin(x-y))atan2उस बिंदु के लिए कोण लौटाता है (जो इसके बराबर है x-y) इसकी सीमा को छोड़कर [-पीआई, पीआई] है।
मैक्स

3
यह परीक्षण सूट को पारित करता है। gist.github.com/bradphelan/7fe21ad8ebfcb43696b8
8:13 पर '13

2
एक लाइन सरल समाधान और मेरे लिए हल (चयनित उत्तर नहीं;)। लेकिन टैन उलटा एक महंगी प्रक्रिया है।
मोहन कुमार

2
मेरे लिए, सबसे सुरुचिपूर्ण समाधान। शर्म की बात है कि यह कम्प्यूटेशनल रूप से महंगा हो सकता है।
फॉक्स

मेरे लिए सबसे सुंदर समाधान के रूप में अच्छी तरह से! मेरी समस्या को पूरी तरह से हल किया है (एक सूत्र है जो मुझे हस्ताक्षरित टर्न कोण देता है जो दो संभव मोड़ दिशाओं / कोणों से छोटा है)।
जुरगेन

41

यदि आपके दो कोण x और y हैं, तो उनके बीच के कोणों में से एक अनुपस्थित है (x - y)। अन्य कोण है (2 * PI) - abs (x - y)। तो 2 कोणों में सबसे छोटे का मान है:

min((2 * PI) - abs(x - y), abs(x - y))

यह आपको कोण का पूर्ण मान देता है, और यह मानता है कि इनपुट सामान्यीकृत हैं (यानी: सीमा के भीतर [0, 2π))।

यदि आप कोण के चिन्ह (यानी: दिशा) को संरक्षित करना चाहते हैं और सीमा के बाहर के कोणों को भी स्वीकार [0, 2π)कर सकते हैं जिन्हें आप ऊपर बता सकते हैं। यहाँ सामान्यीकृत संस्करण के लिए पायथन कोड दिया गया है:

PI = math.pi
TAU = 2*PI
def smallestSignedAngleBetween(x, y):
    a = (x - y) % TAU
    b = (y - x) % TAU
    return -a if a < b else b

ध्यान दें कि %ऑपरेटर सभी भाषाओं में समान व्यवहार नहीं करता है, खासकर जब नकारात्मक मूल्य शामिल होते हैं, इसलिए यदि कुछ साइन समायोजन को पोर्ट करना आवश्यक हो सकता है।


1
@bradgonesurfing यह सच है / है, लेकिन उन चीजों के लिए जांचे जाने के लिए निष्पक्ष होना चाहिए जो मूल प्रश्न में निर्दिष्ट नहीं हैं, विशेष रूप से गैर-सामान्यीकृत इनपुट और साइन-संरक्षण। संपादित उत्तर में दूसरा संस्करण आपके परीक्षणों को पास करना चाहिए।
लॉरेंस गोंसाल्वेस

दूसरा संस्करण भी मेरे लिए काम नहीं करता है। उदाहरण के लिए 350 और 0 का प्रयास करें। इसे -10 लौटाना चाहिए लेकिन -350
kjyv

@kjyv मैं आपके द्वारा वर्णित व्यवहार को पुन: पेश नहीं कर सकता। क्या आप सटीक कोड पोस्ट कर सकते हैं?
लॉरेंस गोंसाल्वेस 23

आह, मुझे क्षमा करें। मैंने आपके संस्करण को बिल्कुल रेड में अजगर और डिग्री के साथ परीक्षण किया है और यह ठीक काम किया है। इसलिए C # के अनुवाद में मेरी गलती रही होगी (अब नहीं है)।
kjyv

2
ध्यान दें कि, पायथन 3 के रूप में, आप वास्तव में ताऊ का उपयोग कर सकते हैं! बस लिखो from math import tau
शार्लत

8

मैं हस्ताक्षरित उत्तर प्रदान करने की चुनौती को जन्म देता हूं:

def f(x,y):
  import math
  return min(y-x, y-x+2*math.pi, y-x-2*math.pi, key=abs)

1
आह ... जवाब एक पायथन फंक्शन है। क्षमा करें, मैं एक पल के लिए पायथन मोड में था। आशा है कि ठीक है।
डेविड जोन्स

मैं अपने कोड में नए फार्मूले को ऊपर की तरफ प्लग करूंगा और देखूंगा कि इसका क्या होता है! (थैंक्यू ^ _ ^)
टॉम जे नोवेल

1
मुझे पूरा यकीन है कि पीटरबी का जवाब भी सही है। और एविली हैकिश। :)
डेविड जोंस

4
लेकिन यह कोई भी
ट्रिगर

जावा के लिए समान सूत्र क्या है? अगर कोण डिग्री में हैं।?
सोली


5

अंकगणितीय (एल्गोरिथम के विपरीत) समाधान:

angle = Pi - abs(abs(a1 - a2) - Pi);

4
यह परीक्षण सूट में विफल रहता है gist.github.com/bradphelan/7fe21ad8ebfcb43696b8
bradgonesurfing

अनुपस्थित होने पर (a-a2) >>> 360 इसके बजाय इसका प्रयोग करें: stackoverflow.com/a/52432897/6050364
एड्रिएल जूनियर

2

C ++ में एक कुशल कोड जो किसी भी कोण और दोनों के लिए काम करता है: रेडियन और डिग्री है:

inline double getAbsoluteDiff2Angles(const double x, const double y, const double c)
{
    // c can be PI (for radians) or 180.0 (for degrees);
    return c - fabs(fmod(fabs(x - y), 2*c) - c);
}

-1

त्रिकोणमितीय कार्यों की गणना करने की कोई आवश्यकता नहीं है। C भाषा में सरल कोड है:

#include <math.h>
#define PIV2 M_PI+M_PI
#define C360 360.0000000000000000000
double difangrad(double x, double y)
{
double arg;

arg = fmod(y-x, PIV2);
if (arg < 0 )  arg  = arg + PIV2;
if (arg > M_PI) arg  = arg - PIV2;

return (-arg);
}
double difangdeg(double x, double y)
{
double arg;
arg = fmod(y-x, C360);
if (arg < 0 )  arg  = arg + C360;
if (arg > 180) arg  = arg - C360;
return (-arg);
}

रेडियन में अंतर = a - b

dif = difangrad(a,b);

डिग्रियों = a - b को डिग्री में दें

dif = difangdeg(a,b);

difangdeg(180.000000 , -180.000000) = 0.000000
difangdeg(-180.000000 , 180.000000) = -0.000000
difangdeg(359.000000 , 1.000000) = -2.000000
difangdeg(1.000000 , 359.000000) = 2.000000

न पाप, न कोस, न तन, .... केवल ज्यामिति !!!!


7
बग! चूंकि आप "M_PI + M_PI" के रूप में #define PIV2, नहीं "(M_PI + M_PI)", लाइन का arg = arg - PIV2;विस्तार होता है arg = arg - M_PI + M_PI, और इसलिए कुछ भी नहीं करता है।
छावनी 7
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.