কোণ তুলনা এবং পার্থক্য কাজ করে


27

আমি কোণগুলির তুলনা করতে এবং তাদের মধ্যে দূরত্ব সম্পর্কে ধারণা পেতে চাই। এই অ্যাপ্লিকেশনটির জন্য, আমি ডিগ্রিতে কাজ করছি তবে এটি রেডিয়ান এবং গ্রেডগুলির জন্যও কাজ করবে। কোণগুলির সাথে সমস্যাটি হ'ল তারা মডিউলার গাণিতিক, অর্থাৎ 0-360 ডিগ্রির উপর নির্ভর করে।

বলুন একটি কোণ 15 ডিগ্রি এবং একটি 45-এ রয়েছে The পার্থক্য 30 ডিগ্রি, এবং 45 ডিগ্রি কোণ 15 ডিগ্রি একের চেয়ে বেশি।

তবে, আপনার যখন 345 ডিগ্রি এবং 30 ডিগ্রি থাকবে তখন এটি ভেঙে যায়। যদিও তারা সঠিকভাবে তুলনা করে, তাদের মধ্যে পার্থক্যটি সঠিক 45 ডিগ্রির পরিবর্তে 315 ডিগ্রি degrees

আমি কীভাবে এটি সমাধান করতে পারি? আমি আলগোরিদিমিক কোড লিখতে পারি:

if(angle1 > angle2) delta_theta = 360 - angle2 - angle1;
else delta_theta = angle2 - angle1;

তবে আমি এমন একটি সমাধান পছন্দ করবো যা তুলনা / শাখাগুলি এড়ায় এবং গাণিতিকের উপর পুরোপুরি নির্ভর করে।


এই সমস্যায়, আমরা কি ধরে নিতে পারি যে প্রদত্ত কোণগুলি [0,360] বা (-সীমাবদ্ধ, + অসীম) সীমাতে রয়েছে? উদাহরণস্বরূপ, অ্যালগরিদমটিও 450 এর সাথে -130 ডিগ্রি তুলনা করে কাজ করা উচিত?
ইগার্সিয়া

ধরুন কোণগুলি এই ব্যাপ্তিতে স্বাভাবিক করা হয়েছে।
থমাস ও

উত্তর:


29

এখানে আমার সরলীকৃত, শাখাবিহীন, তুলনা মুক্ত, কোনও ন্যূনতম / সর্বাধিক সংস্করণ নেই:

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

ইনপুটগুলি যথেষ্ট পরিমাণে সীমাবদ্ধ থাকায় মডুলো সরানো হয়েছে (এটি নির্দেশ করার জন্য মার্টিনকে ধন্যবাদ)।

দুটি অ্যাবস, তিনটি বিয়োগফল।


আপনার মডুলোর দরকার নেই, ইনপুট মানগুলি [0,360] সীমাতে সীমাবদ্ধ ((মূল জমা দেওয়ার বিষয়ে থমাসের মন্তব্য দেখুন)। বেশ ঝরঝরে.
মার্টিন সোজকা

আহ, হ্যাঁ, আপনি ঠিক বলেছেন। আমি এটি চেষ্টা করার সময় আমার কাছে কম কঠোর ইনপুট ছিল।
জেসনডি

তবে আপনি যদি পার্থক্যের চিহ্নটি সংরক্ষণ করতে চান তবে কী বলতে পারেন যে বাম দিকে ছিল?
জ্যাকব ফিলিপস

9

যদিও তারা সঠিকভাবে তুলনা করে, তাদের মধ্যে পার্থক্যটি সঠিক 45 ডিগ্রির পরিবর্তে 315 ডিগ্রি degrees

315 টি ভুল বলে আপনাকে কী মনে করে? এক দিকে, এটি 315 ডিগ্রি, অন্যদিকে এটি 45 টি। আপনি যে কোনও দুটি সম্ভাব্য কোণগুলির মধ্যে সবচেয়ে ছোটটি বেছে নিতে চান এবং এটি অভ্যন্তরীণভাবে শর্তাধীন বলে মনে হয় seems আপনি এটিকে মোড়কের চারপাশে পাটিগণিত (যেমন মডুলাস অপারেটরের মাধ্যমে) দিয়ে সমাধান করতে পারবেন না কারণ আপনি ধীরে ধীরে একটি কোণ বৃদ্ধি করার সাথে সাথে তার মধ্যবর্তী কোণটি 180 টি হিট হওয়া অবধি বাড়তে থাকে এবং তার পরে কমতে শুরু করে।

আমি মনে করি আপনাকে হয় উভয় কোণ পরীক্ষা করতে হবে এবং সিদ্ধান্ত নিতে হবে আপনি কোন দিকটি পরিমাপ করতে চান, বা উভয় দিকনির্দেশনা গণনা করতে হবে এবং কোন ফলাফলটি চান তা সিদ্ধান্ত নিতে হবে।


দুঃখিত আমি স্পষ্ট করা উচিত। যদি আপনি এটি বিপরীতে করেন তবে 30 - 345 হ'ল -315 এবং একটি নেতিবাচক কোণটি খুব বেশি বোঝায় না। আমি অনুমান করি যে আমি দুজনের মধ্যে ক্ষুদ্রতম কোণটি খুঁজছি। অর্থাৎ 45 ডিগ্রি 315 এর চেয়ে ছোট
থমাস

2
তবে কোনও 'বিপরীত' নেই - আপনার কাছে দুটি কোণ এবং 2 ধরণের ঘূর্ণন রয়েছে যা আপনি একটির সাথে অন্য ম্যাচটি তৈরি করতে পারেন। একটি নেতিবাচক কোণ নিখুঁত ধারণা তৈরি করে - এটি সর্বোপরি একটি স্বেচ্ছাচারিত অক্ষ থেকে ঘোরার মাত্রা।
কাইলোটন

আপনি যদি ক্ষুদ্রতম কোণ চান তবে অ্যাবস (এ 1% 180 - এ 2% 180) আপনাকে সেই কোণটি দেবে। এটি আপনাকে দিকনির্দেশটি বলবে না। অ্যাবসগুলি অপসারণ করা আপনাকে "এ 1" থেকে "এ 2" এ যাওয়ার সবচেয়ে ছোট কোণটি দেবে
চিউই গম্বল

2
@ চাবি, হাহ? 180 এবং 0 এর মধ্যে পার্থক্য 0 নয়, এবং 181 এবং 0 এর মধ্যে পার্থক্য 1 নয়
ড্যাশ-টম-ব্যাং

1
@ ড্যাশ-টম-ব্যাং আপনি ঠিক বলেছেন। আমি কী ভাবছিলাম তা আমি জানি না, তবে এখনই এটি আবার দেখার জন্য এটি মোটেও ঠিক হয়নি। আমার আগের মন্তব্য উপেক্ষা করুন।
চিউই গম্বল

4

উভয় শাখা করার এবং তুলনার ফলাফলটিকে একটি বাছাই দেওয়ার কৌশল সর্বদা রয়েছে:

delta_theta = (angle1 > angle2) * (360 - angle2 - angle1)
              + (angle2 > angle1) * (angle2 - angle1);

আমি তুলনা ছাড়াই এটি করার কোনও উপায় জানি না , তবে সাধারণত শাখাটি কোডকে ধীর এবং দীর্ঘ করে তোলে, তুলনা করে না। কমপক্ষে আমার মতে, এটি মার্টিনের উত্তরের চেয়ে বেশি পঠনযোগ্য (কোনও ভাল সি প্রোগ্রামার এটিকে শাখাবিহীন সমতুল্য হিসাবে স্বীকৃতি দেবে এবং এটি কী করছে তা দেখবে), তবে কম দক্ষও।

তবে আমি যেমন আমার মন্তব্যে বলেছি, শাখাবিহীন অ্যালগরিদমগুলি গভীর পাইপলাইন এবং খারাপ ভবিষ্যদ্বাণী সহ প্রসেসরের উপর ভাল - একটি মাইক্রোকন্ট্রোলার সাধারণত একটি ছোট পাইপলাইন থাকে এবং ডেস্কটপ পিসিতে সাধারণত ভাল পূর্বাভাস থাকে, যদি না আপনি গেমিং কনসোলকে লক্ষ্য না করে থাকেন, শাখা সংস্করণ যদি এটি নির্দেশের সংখ্যা হ্রাস করে তবে সম্ভবত এটি সর্বোত্তম পথ।

সর্বদা হিসাবে, প্রোফাইলিং - যা আপনার সিস্টেমের জন্য অপ-গণনার মতো সহজ হতে পারে - আপনাকে আসল উত্তর দেবে।


2

-1 এর মিথ্যা মূল্যায়ন 0 এবং '~', '&' এবং '|' এর সত্য মূল্যায়নকে ধরে নেওয়া হচ্ছে , bitwise হয় না , এবং এবং বা অপারেটার যথাক্রমে, এবং আমরা সঙ্গে কাজ two's-পরিপূর্ণ গাণিতিক করছেন যারা

temp1 := angle1 > angle2
/* most processors can do this without a jump; for example, under the x86 family,
   it's the result of CMP; SETLE; SUB .., 1 instructions */
temp2 := angle1 - angle2
temp1 := (temp1 & temp2) | (~temp1 & -temp2)
/* in x86 again: only SUB, AND, OR, NOT and NEG are used, no jumps
   at this point, we have the positive difference between the angles in temp1;
   we can now do the same trick again */
temp2 := temp1 > 180
temp2 := (temp2 & temp1) | (~temp2 & (360 - temp1))
/* the result is in temp2 now */

+1 কারণ এটি চতুর, তবে একটি মাইক্রোকন্ট্রোলারের উপর এটি সম্ভবত ব্রাঞ্চিং সংস্করণের চেয়ে আরও খারাপ-সম্পাদনকারী।

মাইক্রোকন্ট্রোলারের উপর কিছুটা নির্ভর করে, তবে, হ্যাঁ, এটি সাধারণত এটির পক্ষে উপযুক্ত নয়; একটি (সংক্ষিপ্ত) শর্তসাপেক্ষ লাফ সাধারণত দ্রুত যথেষ্ট is এছাড়াও, তৃতীয় এবং পঞ্চম লাইনগুলিকে এই জাতীয় xor (^) ক্রিয়াকলাপটি ব্যবহার করে কিছুটা দ্রুত হতে পুনরায় লেখা যেতে পারে, তবে আমি তাদের স্পষ্টতার জন্য বর্তমান আকারে রেখেছি: টেম্প 1: = টেম্প 2 ^ ((টেম্প 2 2 -টেম্প 2) & ~ temp1), temp2: = temp1 ^ ((temp1 ((360 - temp1)) এবং ~ temp2)
মার্টিন

1

এই সম্পর্কে কি?

min( (a1-a2+360)%360, (a2-a1+360)%360 )

নেতিবাচক পার্থক্য এড়াতে 360 যোগ করা হয়েছে কারণ একটি নেতিবাচক সংখ্যার একটি মডুলো একটি নেতিবাচক ফলাফল প্রদান করে। তারপরে আপনি দুটি সম্ভাব্য ফলাফলের চেয়ে আরও ছোট পাবেন।

এখনও একটি অন্তর্নিহিত সিদ্ধান্ত আছে, কিন্তু আমি কীভাবে এড়াতে জানি না। মূলত আপনি দুটি কোণকে ঘড়ির কাঁটার বিপরীতে বা ঘড়ির কাঁটার বিপরীতে গণনা করে তুলনা করেন এবং মনে হয় আপনি এই দুটি পার্থক্যের চেয়ে ছোটটি স্পষ্টতই চান। তাদের তুলনা না করে কীভাবে ফলাফল পাওয়া যায় তা আমি জানি না। এটি হ'ল "অ্যাবস", "মিনিট", "সর্বাধিক" বা কিছু অনুরূপ অপারেটর ব্যবহার না করে।


শাখার নির্দেশনা ব্যতীত কমপক্ষে নূন্যতম, সর্বাধিক এবং কীটপথগুলি গণনা করার বিভিন্ন উপায় রয়েছে যদিও এটি একটি মাইক্রোকন্ট্রোলার তাই সম্ভবত শাখাটি সবচেয়ে দ্রুততম উপায়। গ্রাফিক্স.স্ট্যানফোর্ড.এডু

1

আপনার প্রশ্নটি সেগুলির কোনও রেফারেন্স না দিলে, আমি এই ধারনাটিতে কাজ করতে যাচ্ছি যে আপনার কোণ গণনা প্রশ্নটি দুটি ভেক্টরের মধ্যে ন্যূনতম কোণটি জানতে চাওয়ার থেকে উদ্ভূত ।

যে গণনা সহজ। ধরে নিলাম A এবং B আপনার ভেক্টর:

angle_between = acos( Dot( A.normalized, B.normalized ) )

যদি আপনার কাছে ভেক্টর না থাকে এবং আপনি এই পদ্ধতিটি ব্যবহার করতে চান তবে আপনি কোণ দ্বারা প্রদত্ত ইউনিট দৈর্ঘ্য ভেক্টরগুলি তৈরি করতে পারেন new Vector2( cos( angle ), sin ( angle ) )


1
আমি যে প্রসেসরে কাজ করছি তা হ'ল একটি ছোট মাইক্রোকন্ট্রোলার। কেবলমাত্র কোণগুলির মধ্যে পার্থক্য পেতে ভেক্টর তৈরি করতে ট্রিগার ফাংশনগুলি ব্যবহার করা বোধগম্য নয়, প্রতিটি চক্রটি মূল্যবান।
থমাস হে

1
একটি মাইক্রোকন্ট্রোলারে আমি এক ধরনের আশ্চর্য হয়েছি শাখা ব্যবহার করা ভাল নয়, তবে আপনি যদি সত্যিই শাখা প্রশাখা এড়াতে চান তবে আমার উত্তরে পাটিগণিতের খুব বেশি কিছু নেই।
জেসনডি

ঠিক আছে, একটি শাখা দুটি চক্র এবং একটি অ্যাড / বিয়োগ / ইত্যাদি একটি চক্র, তবে শাখাগুলি অতিরিক্ত প্রোগ্রামের মেমরি গ্রহণ করে। এটি সমালোচনা নয়, তবে এটি দুর্দান্ত হবে।
থমাস হে

আমি পেতে আপনার উত্তর বোধ সঠিক এবং খনি ভুল, কিন্তু আমি প্রায় আমার মাথা পেতে পারে না কেন যে ক্ষেত্রে দেখা যায়। :)
কাইলোটন

1

নিখুঁত মান ফাংশনের পরিবর্তে বিটওয়াইজ ক্রিয়াকলাপ বাদে জেসনডির উত্তর হিসাবে সমান।

এটি ধরে নেওয়া হচ্ছে আপনার 16-বিট সংক্ষিপ্ত পূর্ণসংখ্যা রয়েছে!

short angleBetween(short a,short b) {
    short x = a - b;
    short y = x >> 15;
    y = ((x + y) ^ y) - 180;
    return 180 - ((x + y) ^ y);
}


0

যেহেতু আপনি কেবল পাটিগণিত ছাড়াই শাখা এবং "জটিল" ক্রিয়াকলাপগুলি অপসারণের বিষয়ে যত্নশীল, তাই আমি এটি সুপারিশ করব:

min(abs(angle1 - angle2), abs(angle2 - angle1))

absসমস্ত কোণ ইতিবাচক হওয়া সত্ত্বেও আপনাকে এখনও সেখানে প্রবেশ করতে হবে। অন্যথায়, সর্বাধিক নেতিবাচক ফলাফল সর্বদা চয়ন করা হবে (এবং আব এবং বাহ তুলনা করার সময় ইতিবাচক, অনন্য a এবং b এর জন্য সর্বদা ঠিক একটি নেতিবাচক উত্তর থাকবে)।

দ্রষ্টব্য: এটি কোণ 1 এবং কোণ 2 এর মধ্যে দিক রক্ষা করবে না। কখনও কখনও আপনার এআই প্রয়োজনে এটি প্রয়োজন।

এটি সিজে-র উত্তরের অনুরূপ, তবে সমস্ত মডুলুগুলি সরিয়ে দেয়। আমি কি চক্র খরচ জানি না abs, কিন্তু আমি এটা বলতে কি খরচ হয় 1 বা 2. কঠিন অনুমান যাচ্ছি minহিসাবে ভাল। হতে পারে 3? সুতরাং বিয়োগফল প্রতি 1 টি চক্রের পাশাপাশি, এই লাইনের কোথাও 4 থেকে 9 এর কাছাকাছি ব্যয় হওয়া উচিত।


0

পান ছোট আপেক্ষিক কোণ স্বাক্ষরিত (+/-) ফর্ম দৃষ্টিকোণ থেকে আছে দিকে চান :

  • সর্বোচ্চ 180 ডিগ্রি | পিআই রেডিয়ান
  • স্বাক্ষরিত যদি অ্যান্টল্লক দিকের
  • + যদি ঘড়ির কাঁটার দিকে সাইন ইন করেন

ডিগ্রী

PITAU = 360 + 180 # for readablility
signed_diff = ( want - have + PITAU ) % 360 - 180

রেডিয়ানে

PI = 3.14; TAU = 2*PI; PITAU = PI + TAU;
signed_diff = ( want - have + PITAU ) % TAU - PI

যুক্তিসহ ব্যাখ্যা

আমি এই থ্রেডটি পেরিয়ে এসেছি এবং আমি এটি বের করার পরে, এমন কোনও সমাধান খুঁজছি যা মডুলো এড়ায়; এখনও পর্যন্ত আমি কিছুই খুঁজে পাইনি । এই সমাধানটি দৃষ্টিকোণ সাইন সংরক্ষণের জন্য, যেমন @ জ্যাকব-ফিলিপস এই মন্তব্যটি বলেছেন । আপনার যদি স্বল্পতম স্বাক্ষরিত স্বাক্ষরিত কোণ প্রয়োজন হয় তবে সস্তা সমাধান রয়েছে।


0

এটি একটি পুরানো প্রশ্ন তবে আমি একই ক্ষেত্রে চলে এসেছি - শাখাগুলি এবং ভারী গণিত ছাড়াই স্বাক্ষরিত কৌণিক পার্থক্য করতে হয়েছিল। এটিই আমি শেষ করেছি:

int d = (a - b) + 180 + N * 360; // N = 1, 2 or more.
int r = (d / 360) * 360;
return (d - r) - 180;

সীমাবদ্ধতাটি হ'ল 'খ' এর 'এ' এর তুলনায় 'এন' রোটেশন বেশি হওয়া উচিত নয়। যদি আপনি এটি নিশ্চিত করতে না পারেন এবং অতিরিক্ত ক্রিয়াকলাপের অনুমতি দিতে পারেন তবে এটি প্রথম লাইন হিসাবে ব্যবহার করুন:

int d = ((a % 360) - (b % 360)) + 540;

আমি এই পোস্টে 13 তম মন্তব্যটি থেকে ধারণা পেয়েছেন: http://blog.lexique-du-net.com/index.php?post/Calculate-the-real-difference-between-two-angles-keeping-the- চিহ্ন


-1

আমার ধারণা আমি বলতে পারি

angle1=angle1%360;
angle2=angle2%360;
var distance = Math.abs(angle1-angle2);
//edited
if(distance>180)
  distance=360-distance;

অবশ্যই, কোণ বিবেচনা করে ডিগ্রীতে পরিমাপ করা হয়।


1
আমি বিশ্বাস করি না যে এটি সমস্যার সমাধান করে। 345% 360 == 345, এবং অ্যাবস (345-30) এখনও 315.
গ্রেগরি অ্যাভেরি-ওয়েয়ার

@ গ্রেগরি: ঠিক আছে! আমি ভুলের জন্য দুঃখিত আমি উত্তরটি সম্পাদনা করছি, এই নতুনটি পরীক্ষা করুন। :)
বিষ্ণু

1
যাইহোক, কোণ 1 = কোণ1% 360; angle2 = angle2% 360; var দূরত্ব = ম্যাথ.এবস (কোণ 1-কোণ 2); ভার দূরত্ব = ম্যাথ.এবস (কোণ 1-কোণ 2)% 360 এর মতোই - ধীর।
মার্টিন সোজকা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.