আপনার কোড পুরোপুরি ঠিক আছে
আপনি একেবারে সঠিক এবং আপনার শিক্ষক ভুল। অতিরিক্ত জটিলতা যুক্ত করার কোনও কারণ নেই, কারণ এটি ফলাফলকে মোটেই প্রভাবিত করে না। এমনকি এটি একটি বাগ প্রবর্তন করে। (নিচে দেখ)
প্রথমত, n
শূন্য কিনা পৃথক চেক স্পষ্টতই সম্পূর্ণ অপ্রয়োজনীয় এবং এটি উপলব্ধি করা খুব সহজ। সত্যি কথা বলতে কি আমি আসলে আপনার শিক্ষকদের যোগ্যতা নিয়ে প্রশ্ন করি যদি সে সম্পর্কে এই বিষয়ে আপত্তি থাকে। তবে আমি অনুমান যে সময়ে সময়ে প্রত্যেকের একটি মস্তিষ্ক ফার্ট হতে পারে। যাইহোক, আমি মনে করি এটি while(n)
পরিবর্তন করা উচিত while(n != 0)
কারণ এটি অতিরিক্ত লাইন ব্যয় না করে কিছুটা অতিরিক্ত স্পষ্টতা যুক্ত করে। যদিও এটি একটি ছোটখাটো জিনিস।
দ্বিতীয়টি কিছুটা বোধগম্য, তবে তিনি এখনও ভুল।
এটি সি 11 স্ট্যান্ডার্ড 6.5.5.p6 যা বলে:
যদি ভাগফল a / b উপস্থাপনযোগ্য হয় তবে এক্সপ্রেশনটি (a / b) * b + a% b এর সমান হবে; অন্যথায়, দু'এ / বি এবং% বি উভয়ের আচরণ সংজ্ঞায়িত।
পাদটীকা এই বলে:
একে প্রায়শই "শূন্যের দিকে কাটা" বলা হয়।
শূন্য মানে দিকে truncation যে জন্য পরম মান a/b
জন্য পরম মান সমান (-a)/b
সবার জন্য a
এবং b
যেটা ঘুরে মানে আপনার কোড পুরোপুরি জরিমানা করে।
মডুলো সহজ গণিত, তবে বিপরীত হতে পারে
তবে, আপনার শিক্ষকের একটি বক্তব্য রয়েছে যে আপনার সাবধান হওয়া উচিত, কারণ আপনি ফলাফলটি বানাচ্ছেন তা এখানে সত্যই গুরুত্বপূর্ণ। a%b
উপরের সংজ্ঞা অনুসারে গণনা করা সহজ গণিত, তবে এটি আপনার অন্তর্দৃষ্টির বিপরীতে যেতে পারে। গুণ এবং বিভাগের জন্য, অপারেন্ডদের সমান চিহ্ন থাকলে ফলাফলটি ইতিবাচক হয়। তবে এটি যখন মডুলোর ক্ষেত্রে আসে, ফলাফলটিতে প্রথম অপারেন্ডের মতো একই চিহ্ন থাকে । দ্বিতীয় অপারেন্ডটি সাইনকে মোটেই প্রভাবিত করে না। উদাহরণস্বরূপ, 7%3==1
কিন্তু (-7)%(-3)==(-1)
।
এটি প্রদর্শিত একটি স্নিপেট এখানে:
$ cat > main.c
#include <stdio.h>
void f(int a, int b)
{
printf("a: %2d b: %2d a/b: %2d a\%b: %2d (a%b)^2: %2d (a/b)*b+a%b==a: %5s\n",
a, b ,a/b, a%b, (a%b)*(a%b), (a/b)*b+a%b == a ? "true" : "false");
}
int main(void)
{
int a=7, b=3;
f(a,b);
f(-a,b);
f(a,-b);
f(-a,-b);
}
$ gcc main.c -Wall -Wextra -pedantic -std=c99
$ ./a.out
a: 7 b: 3 a/b: 2 a%b: 1 (a%b)^2: 1 (a/b)*b+a%b==a: true
a: -7 b: 3 a/b: -2 a%b: -1 (a%b)^2: 1 (a/b)*b+a%b==a: true
a: 7 b: -3 a/b: -2 a%b: 1 (a%b)^2: 1 (a/b)*b+a%b==a: true
a: -7 b: -3 a/b: 2 a%b: -1 (a%b)^2: 1 (a/b)*b+a%b==a: true
সুতরাং, ব্যঙ্গাত্মকভাবে, আপনার শিক্ষক ভুল হয়ে নিজের বক্তব্য প্রমাণ করেছেন।
আপনার শিক্ষকের কোডটি ত্রুটিযুক্ত
হ্যাঁ, এটি আসলে। যদি ইনপুটটি হয় INT_MIN
এবং আর্কিটেকচার দুটিটির পরিপূরক এবং বিট প্যাটার্ন যেখানে সাইন বিট 1 এবং সমস্ত মান বিট 0 হয় কোনও ফাঁদ মান নয় (ফাঁদ মান ব্যতীত দু'জনের পরিপূরক ব্যবহার করা খুব সাধারণ) তবে আপনার শিক্ষকের কোডটি অপরিবর্তিত আচরণ করবে লাইনে n = n * (-1)
। আপনার কোডটি - যদি কখনও এত সামান্য হয় - তবে তার থেকে ভাল । এবং কোডটিকে অপ্রয়োজনীয় জটিল করে একেবারে শূন্য মান অর্জন করে একটি ছোট বাগ প্রবর্তনের কথা বিবেচনা করে, আমি বলতে পারি যে আপনার কোডটি অনেক ভাল।
অন্য কথায়, সংকলনগুলিতে যেখানে INT_MIN = -32768 (যদিও ফলস্বরূপ ফাংশনটি <-32768 বা> 32767 হয় এমন কোনও ইনপুট গ্রহণ করতে পারে না), -32768 এর বৈধ ইনপুট অপরিজ্ঞাত আচরণের কারণ, কারণ - (- 32768i16) 16-বিট পূর্ণসংখ্যা হিসাবে প্রকাশ করা যায় না। (আসলে, -32768 সম্ভবত কোনও ভুল ফলাফল সৃষ্টি করতে পারে না, কারণ - (- 32768i16) সাধারণত -32768i16 এ মূল্যায়ন করে এবং আপনার প্রোগ্রামটি সঠিকভাবে নেতিবাচক সংখ্যাগুলি পরিচালনা করে)) (SHRT_MIN সংকলকটির উপর নির্ভর করে -32768 বা -32767 হতে পারে))
তবে আপনার শিক্ষক স্পষ্টতই বলেছেন যে n
এটি [-10 ^ 7 এর মধ্যে থাকতে পারে; 10 ^ 7]। একটি 16-বিট পূর্ণসংখ্যা খুব ছোট; আপনাকে [কমপক্ষে] একটি 32-বিট পূর্ণসংখ্যা ব্যবহার করতে হবে। ব্যবহার করা int
সম্ভবত তার কোডটিকে নিরাপদ বলে মনে হতে পারে, কেবলমাত্র এটি ছাড়াও int
32-বিট পূর্ণসংখ্যার প্রয়োজন হয় না। আপনি যদি 16-বিটের আর্কিটেকচারের জন্য সংকলন করেন তবে আপনার কোড স্নিপেট উভয়ই ত্রুটিযুক্ত। তবে আপনার কোডটি এখনও অনেক বেশি ভাল কারণ এই দৃশ্যটি INT_MIN
তার সংস্করণটি সহ উল্লিখিত বাগটি পুনরায় পরিচয় করে । এড়াতে, আপনি long
পরিবর্তে লিখতে পারেন int
, যা উভয় স্থাপত্যের মধ্যে 32-বিট পূর্ণসংখ্যা। এ long
এর গ্যারান্টিযুক্ত যে কোনও মান [-2147483647; রেঞ্জের মধ্যে রাখতে সক্ষম হবে; 2147483647]। সি 11 স্ট্যান্ডার্ড 5.2.4.2.1 LONG_MIN
প্রায়শই হয়-2147483648
কিন্তু সর্বোচ্চ অনুমোদিত মানের জন্য (হ্যাঁ, সর্বোচ্চ, এটি একটি ঋণাত্মক সংখ্যা থাকবে) LONG_MIN
হয় 2147483647
।
আমি আপনার কোডে কি পরিবর্তন করব?
আপনার কোড যেমন হয় ঠিক তেমনি এগুলি আসলে অভিযোগ নয়। এটি এর মতো আরও যদি আমি সত্যিই আপনার কোড সম্পর্কে কিছু বলতে চাই তবে কিছু ছোট ছোট জিনিস আছে যা এটি কেবল একটি ছোট্ট বিটকে আরও পরিষ্কার করতে পারে।
- ভেরিয়েবলের নামগুলি কিছুটা ভাল হতে পারে তবে এটি একটি সংক্ষিপ্ত ফাংশন যা বোঝা সহজ, সুতরাং এটি কোনও বড় বিষয় নয়।
- আপনি শর্তটি থেকে পরিবর্তন করতে
n
পারেন n!=0
। শব্দার্থকভাবে, এটি 100% সমতুল্য, তবে এটি এটি কিছুটা স্পষ্ট করে তোলে।
- ঘোষিতকরণের ঘোষণাকে
c
(যার নাম দিয়েছি digit
) এটি লুপের ভিতরে থাকায় এটি কেবল সেখানে ব্যবহৃত হয়েছে it's
long
এটি পুরো ইনপুট সেটটিকে পরিচালনা করতে পারে তা নিশ্চিত করতে যুক্তির ধরণটি পরিবর্তন করুন।
int sum_of_digits_squared(long n)
{
long sum = 0;
while (n != 0) {
int digit = n % 10;
sum += (digit * digit);
n /= 10;
}
return sum;
}
প্রকৃতপক্ষে, এটি কিছুটা বিভ্রান্তিকর হতে পারে কারণ - উপরে উল্লিখিত হিসাবে - পরিবর্তনশীল digit
একটি নেতিবাচক মান পেতে পারে, কিন্তু একটি সংখ্যা নিজেই হয় না হয় ইতিবাচক বা নেতিবাচক। এর চারপাশে কয়েকটি উপায় রয়েছে তবে এটি সত্যিই নিটপিকিং। এবং আমি এই জাতীয় ছোট বিবরণটির জন্য যত্ন নিই না। বিশেষত শেষ অঙ্কের জন্য পৃথক ফাংশনটি এটি খুব দূরে নিয়ে যাচ্ছে। হাস্যকরভাবে, আপনার শিক্ষকদের কোডটি আসলে সমাধান করে এমন একটি বিষয়।
- পরিবর্তনটি সম্পূর্ণরূপে এড়িয়ে
sum += (digit * digit)
যান sum += ((n%10)*(n%10))
এবং এড়িয়ে যান digit
।
digit
Negative ণাত্মক হলে এর সাইন পরিবর্তন করুন । তবে কোডটি আরও জটিল করার বিরুদ্ধে আমি দৃ just়ভাবে পরামর্শ দেব কেবলমাত্র একটি পরিবর্তনশীল নামটি বোঝার জন্য। এটি একটি খুব শক্ত কোড গন্ধ।
- একটি পৃথক ফাংশন তৈরি করুন যা শেষ অঙ্কটি বের করে।
int last_digit(long n) { int digit=n%10; if (digit>=0) return digit; else return -digit; }
আপনি যদি সেই ফাংশনটি অন্য কোথাও ব্যবহার করতে চান তবে এটি দরকারী।
- এটির নাম দিন
c
যা আপনি মূলত করেন। এই পরিবর্তনশীল নামটি কোনও কার্যকর তথ্য দেয় না, তবে অন্যদিকে, এটিও বিভ্রান্তিমূলক নয়।
তবে সত্যি বলতে, এই মুহুর্তে আপনার আরও গুরুত্বপূর্ণ কাজ করা উচিত। :)
n = n * (-1)
একটি হাস্যকর লেখার উপায়n = -n
; এটি কেবলমাত্র একাডেমিকই ভাবতে পারে। রিডানড্যান্ট প্রথম বন্ধনী যুক্ত করা যাক।