Learn C Programming

lesson ৩ / ৭ · Variable আর data type

Module ২ · Variable আর data type

Floating point: float, double, আর 0.1 কেন ঠিক 0.1 নয়

Freeপড়া

এই lesson-এ যা শিখবে

  • বুঝেশুনে float বা double বাছতে পারবে, আর এই track কেন সবসময় double নেয় বলতে পারবে।
  • এক অনুচ্ছেদে বোঝাতে পারবে 0.1 + 0.2 কেন 0.3 না।
  • দুইটা দশমিক সংখ্যা == দিয়ে না মিলিয়ে একটা সহনসীমা দিয়ে মেলাতে পারবে।

Maria-র দোকানের till তিনটা দাম যোগ করে এমন একটা মোট ছাপে, যেটা এক পয়সা কম। ও চারবার কাগজে মিলিয়ে দেখে। কাগজও ঠিক, মেশিনও ঠিক, অথচ দুইটা মেলে না।

কেউ ভুল করেনি। একটা দশমিক সংখ্যা binary বাক্সে ঠিকঠাক ধরে না, যেমন এক তৃতীয়াংশ দশমিকে ধরে না। এই lesson সেটা নিয়ে চলার কৌশল।

Binary বাক্সে একটা দশমিক সংখ্যা

এক তৃতীয়াংশ দশমিকে লেখো, পাও 0.333333, যতক্ষণ লিখতে চাও ততক্ষণ। যেখানেই থামো, তুমি এমন কিছু লিখেছ যেটা এক তৃতীয়াংশ না।

Computer-রও একই সমস্যা, দুই ভিত্তিতে। ওর অঙ্কগুলো হলো অর্ধেক, চার ভাগের এক, আট ভাগের এক আর ষোলো ভাগের এক, আর ওগুলোর কোনো যোগফলই ঠিক এক দশমাংশে গিয়ে পড়ে না।

তাই তুমি C-তে 0.1 লিখলে মেশিন তার সবচেয়ে কাছের যে মানটা বানাতে পারে সেটাই রাখে। ওই মানটা কাছাকাছি, আর ওটা 0.1 না।

#include <stdio.h>

int main(void)
{
    double a = 0.1;
    double b = 0.2;

    printf("0.1 is stored as : %.20f\n", a);
    printf("0.2 is stored as : %.20f\n", b);
    printf("0.3 is stored as : %.20f\n", 0.3);
    return 0;
}
0.1 is stored as : 0.10000000000000000555
0.2 is stored as : 0.20000000000000001110
0.3 is stored as : 0.29999999999999998890

%.20f বিন্দুর পরে বিশটা ঘর চায়, আর ওভাবেই তুমি দেখতে পাও ভেতরে আসলে কী আছে। তোমার লেখা আর সব program ছয় ঘর ছেপেছে আর এই পুরোটা লুকিয়ে রেখেছে।

তাই তোমার source-এ লেখা একটা দশমিক literal হলো একটা অনুরোধ, আর তুমি পাও মেশিনের বানাতে পারা সবচেয়ে কাছের মানটা।

0.1-র সবচেয়ে কাছের double-গুলো আর তাদের মাঝের ফাঁক এক দশমাংশের কাছে যে double-গুলো আছে একটা double 0.09999999999999999167 ঠিক 0.1 এখানে কোনো double পড়ে না C 0.1-র জন্য যা রাখে 0.10000000000000000555 তার পরেরটা 0.10000000000000001943 এখানে পাশাপাশি দুইটা double-র ফাঁক প্রায় 0.0000000000000000139। মাঝের প্রতিটা দশমিককে একটা বেছে নিতে হয়। 0.1 ডানেরটা বাছে।
ছবি 1। 0.1-র কাছের double-গুলো বেড়ার খুঁটির সারির মতো। ঠিক মানটা দুই খুঁটির মাঝে পড়ে, তাই C কাছের খুঁটিটা রাখে।

float আর double: কে কতটা অঙ্ক ঠিক রাখে

দশমিকের জন্য C তোমাকে দুই মাপের বাক্স দেয়, যেগুলো তুমি সত্যিই ব্যবহার করবে।

Typeমাপঠিক রাখে যত অঙ্কসবচেয়ে বড় মানprintf
float4 byteপ্রায় 7প্রায় 3.4 গুণ 10-র 38 ঘাত%f
double8 byteপ্রায় 15 বা 16প্রায় 1.7 গুণ 10-র 308 ঘাত%f
long doubleএখানে 16 byte18 বা তার বেশিআরও বড়%Lf

"ঠিক রাখে যত অঙ্ক" সংখ্যাটাই আসল, আর ওটা ফুরিয়ে যেতে তুমি চোখে দেখতে পারো।

#include <stdio.h>

int main(void)
{
    float  as_float  = 3.141592653589793f;
    double as_double = 3.141592653589793;

    printf("float : %.15f\n", as_float);
    printf("double: %.15f\n", as_double);
    return 0;
}
float : 3.141592741012573
double: 3.141592653589793

দুইটা লাইন অঙ্ক ধরে ধরে মেলাও। সাতটা অঙ্ক পর্যন্ত মেলে, তারপর float বানিয়ে বানিয়ে বলছে।

সাধারণভাবে double নাও। তুমি যেসব processor ব্যবহার করবে তার কোনোটাতেই ওটা ধীর না, আর বাঁচানো 4 byte কখনো হারানো আট অঙ্কের সমান না।

প্রথম literal-র শেষের f-টা খেয়াল করো। ওটা ছাড়া সংখ্যাটা একটা double হয়, তারপর সেটা float-এ চেপে ঢোকে, মানে একই উত্তর একটু ঘুরপথে।

0.1 যোগ 0.2-র সমস্যা, বিশ ঘর পর্যন্ত ছাপা

এই program-টা প্রতিটা C শিক্ষার্থীর ঠিক একবার চালানো উচিত, আর তারপর সারাজীবন মনে রাখা উচিত।

#include <stdio.h>

int main(void)
{
    double a = 0.1;
    double b = 0.2;
    double sum = a + b;

    printf("0.1 + 0.2 = %.20f\n", sum);
    printf("0.3       = %.20f\n", 0.3);
    printf("are they the same? %d\n", sum == 0.3);
    return 0;
}
0.1 + 0.2 = 0.30000000000000004441
0.3       = 0.29999999999999998890
are they the same? 0

0.3-র কাছের দুইটা মান যোগ হলো, আর উত্তরটা এমন একটা বেড়ার খুঁটিতে গিয়ে পড়ল, যেটা 0.3 নিজে যেখানে পড়ে তার থেকে আলাদা।

শেষ লাইনটা আরও একটা জিনিস দেখায়, যেটা আগেভাগে জেনে রাখা ভালো। C-তে একটা তুলনা হলো একটা expression, আর তার মান 1 বা 0। আমরা এইমাত্র যেভাবে করলাম, সেভাবে তুমি সেটা ছাপতে পারো।

তাই দুইটা দশমিক সংখ্যায় == জিজ্ঞেস করে, দুইটা খুঁটি কি একই খুঁটি। তুমি প্রায় কখনোই ওই প্রশ্নটা করতে চাওনি।

সহনসীমা দিয়ে মেলানো

তুমি আসলে জানতে চেয়েছিলে "এরা কি এতটা কাছে যে এক ধরা যায়"। তাই সেটাই জিজ্ঞেস করো।

<math.h>-র fabs একটা পার্থক্যের মাপ দেয়, চিহ্ন বাদ দিয়ে। ওই মাপটাকে একটা ছোট সংখ্যার সঙ্গে মেলাও, যাকে প্রায়ই বলে epsilon।

#include <stdio.h>
#include <math.h>

int main(void)
{
    double sum = 0.1 + 0.2;
    double epsilon = 1e-9;

    printf("the difference  : %.20f\n", fabs(sum - 0.3));
    printf("close enough?   : %d\n", fabs(sum - 0.3) < epsilon);
    return 0;
}
the difference  : 0.00000000000000005551
close enough?   : 1

1e-9 হলো 0.000000001-র বৈজ্ঞানিক লেখা। সাধারণ মাপের সংখ্যার জন্য এটা যুক্তিসঙ্গত epsilon, আর খুব বড় বা খুব ছোট সংখ্যার জন্য খারাপ।

কিছু system-এ math library জোড়া লাগাতে command line-এ -lm লাগে। Playground ওটা আগে থেকেই পাঠায়, তাই সেখানে fabs বাড়তি কিছু ছাড়াই চলে।

তাই নিয়মটা হলো: দুইটা দশমিক সংখ্যার মধ্যে কখনো == না, সবসময় একটা পার্থক্যকে বুঝেশুনে বাছা সহনসীমার সঙ্গে মেলানো।

Integer ভাগ, আর গড়ের ফাঁদ

C-তে দুইটা পূর্ণসংখ্যা ভাগ করলে পূর্ণসংখ্যাই পাও। ভগ্নাংশটা round হয় না; ওটা ফেলে দেওয়া হয়।

#include <stdio.h>

int main(void)
{
    int a = 7;
    int b = 2;

    printf("int / int         : %d\n", a / b);
    printf("stored in a double: %f\n", (double)(a / b));
    printf("done as decimals  : %f\n", a / (double)b);
    return 0;
}
int / int         : 3
stored in a double: 3.000000
done as decimals  : 3.500000

মাঝের লাইনটাই মানুষকে ধরে। Variable-টা একটা double, আর যে মানটা ওতে ঢুকেছে সেটা ঢোকার আগেই নষ্ট হয়ে গেছে।

সমাধানটা ভাগের উপর বসে, ফলের উপর না। এক পাশকে দশমিক type বানাও, আর পুরো ভাগটাই দশমিকে হবে।

তাই (a + b + c) / 3 একটা পূর্ণসংখ্যা, আর (a + b + c) / 3.0 না। একটা অক্ষর।

ছাপা: %f, %.2f, %e আর %g

একটা double-র মান একটাই, আর সেটা দেখানোর রকম অনেক।

একই সংখ্যা ছাপার চার রকম

double v = 1234.5678;

printf("%f",   v)      1234.567800     ছয় ঘর, সবসময়
printf("%.2f", v)      1234.57         দুই ঘর, round করা
printf("%e",   v)      1.234568e+03    বৈজ্ঞানিক লেখা
printf("%g",   v)      1234.57         ছোট রূপ, ও নিজেই বাছে
  • %f ছয় ঘর ছাপে, ওগুলোর মানে থাকুক বা না থাকুক।
  • Judge সাধারণত %.2f চায়। বিন্দুর পরের সংখ্যাটা ঘরের গোনা।
  • যে মানের মাপ আগে থেকে জানো না, তার জন্য %e ভালো।
  • scanf-এ একটা double-র জন্য লাগে %lf, %f না। এটা সবাইকে একবার ধরে।

ছাপার সময় যে মানটা রাখা আছে সেটাই round হয়, তুমি যা লিখেছিলে সেটা না। সেজন্যই 1.005-র %.2f হলো 1.00, যেমনটা পরের Example দেখায়।

দশমিক type কখন একদমই ব্যবহার করবে না

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

ব্যাংক পয়সা রাখে, টাকা না। দোকান পয়সা রাখে। Invoicing system সেন্ট রাখে। তখন প্রতিটা যোগ নিখুঁত, আর দশমিক বিন্দুটা কেবল ছাপার সময় ফেরত বসে।

তাই যে নিয়মটা প্রতিটা পেশাদার programmer-র সঙ্গে সঙ্গে ঘোরে: দশমিক মাপার জন্য, পূর্ণসংখ্যা গোনার জন্য। টাকা গোনার জিনিস।

Example 1: সবচেয়ে ছোট চমক

এক লাইন হিসাব, দুইবার ছাপা। ছয় ঘর সমস্যাটা লুকায় আর বিশ ঘর দেখিয়ে দেয়।

#include <stdio.h>

int main(void)
{
    double third = 1.0 / 3.0;

    printf("six places   : %f\n", third);
    printf("twenty places: %.20f\n", third);
    return 0;
}
six places   : 0.333333
twenty places: 0.33333333333333331483

দ্বিতীয় লাইনটা প্রায় ষোলো অঙ্কের পরে আর 3 থাকে না। Table-র ওই "প্রায় 15 বা 16 অঙ্ক" কথাটা এখানে সরাসরি চোখে দেখা যাচ্ছে।

Run in Compiler
Example 2: সহনসীমা, লিখে দেখানো

দুইটা মান যাদের সমান হওয়ার কথা, এক program-এ দুইভাবে মেলানো।

#include <stdio.h>
#include <math.h>

int main(void)
{
    double sum = 0.1 + 0.2;
    double target = 0.3;
    double epsilon = 1e-9;

    printf("with ==        : %d\n", sum == target);
    printf("with tolerance : %d\n", fabs(sum - target) < epsilon);
    printf("the difference : %.20f\n", fabs(sum - target));
    return 0;
}
with ==        : 0
with tolerance : 1
the difference : 0.00000000000000005551

পার্থক্যটা প্রায় এক কোটি ভাগের এক কোটি ভাগের পাঁচ শতাংশের মতো। Epsilon একশো কোটি ভাগের এক, যেটা অনেক বড়, তাই দ্বিতীয় উত্তরটা 1।

Run in Compiler
Example 3: Maria-র till, beginner আসলে যেটা লেখে

2.675 টাকার একটা bill-র লাইন। একবার double হিসেবে, একবার long long-এ পূর্ণ পয়সা হিসেবে।

#include <stdio.h>

int main(void)
{
    double taka = 2.675;
    long long paisa = 268;          /* the same price, rounded to paisa first */

    printf("as a double, 2 places : %.2f\n", taka);
    printf("as a double, 20 places: %.20f\n", taka);
    printf("as whole paisa        : %lld.%02lld\n", paisa / 100, paisa - (paisa / 100) * 100);
    return 0;
}
as a double, 2 places : 2.67
as a double, 20 places: 2.67499999999999982236
as whole paisa        : 2.68

Till ছাপল 2.67 আর ক্রেতা আশা করেছিল 2.68। খারাপভাবে round কিছুই হয়নি: রাখা মানটা সত্যিই 2.675-র নিচে, তাই দুই ঘর মানে 2.67।

তৃতীয় লাইনটাই পেশাদার উত্তর। System-র কিনারায় একবার পয়সায় round করো, তারপর প্রতিটা যোগ পূর্ণ পয়সায় করো, যেখানে কিছুই সরে যেতে পারে না।

Run in Compiler

এটা কোথায় কাজে লাগছে

  • খেলার physics loop। Unreal আর Godot দুইটাই অবস্থান আর গতি float-এ রাখে, কারণ এক frame-এ ওরকম লক্ষ লক্ষ লাগে আর এক মিটারের জন্য 7 অঙ্কই যথেষ্ট। বিশাল খোলা দুনিয়ায় সীমাটা ছুঁয়ে যায়, তখন double-এ যেতে হয়।
  • GPS-র স্থানাঙ্ক। float-এ অক্ষাংশ প্রায় এক মিটার পর্যন্ত নিখুঁত; double-এ এক মিলিমিটারেরও অনেক কম পর্যন্ত। Mapping-র software ঠিক এই কারণেই double ব্যবহার করে।
  • Audio। একটা WAV file-র sample হলো 16 bit integer, কিন্তু audio engine-র ভেতরে মেশানো আর filter করার প্রতিটা ধাপ float-এ হয়, তারপর বেরোনোর সময় আবার বদলে নেওয়া হয়।
  • ব্যাংকিং। Core banking system আর Stripe-র API, দুইটাই টাকার পরিমাণ রাখে সবচেয়ে ছোট এককের পূর্ণসংখ্যা হিসেবে। Stripe-র API 1099 নেয় আর বোঝায় 10.99, একটা integer ঘরে।
  • Patriot missile battery, Dhahran, 1991। System সময় গুনত দশ ভাগের এক second-এ, একটা 24 bit fixed-point মানে, যেটা এক দশমাংশ ঠিকভাবে ধরতে পারত না। একশো ঘণ্টা চলার পরে ঘড়িটা প্রায় এক তৃতীয়াংশ second সরে গিয়েছিল, যেটা missile-র হিসাবে 600 মিটার।

যে ভুলগুলো সবাই করে

১. দশমিক মান %d দিয়ে ছাপা।

double price = 3.5;
printf("%d\n", price);

Playground-র GCC 12 কিছুই বলে না, কারণ format-র পরীক্ষাটা -Wall-র পিছনে থাকে। আমাদের দৌড়ে ওটা ছেপেছে 0, আর তোমার জন্যও একই ছাপবে এমন কোনো কথা নেই। নিজের মেশিনে gcc -Wall বলে warning: format '%d' expects argument of type 'int', but argument 2 has type 'double'। %f ব্যবহার করো।

২. double-কে %f দিয়ে পড়া।

double d = 0.0;
scanf("%f", &d);
printf("%f\n", d);

Playground-এ নীরব; input 3.5 দিলে ছেপেছে 0.000000। scanf-কে বলা হয়েছিল 8 byte-র বাক্সে 4 byte লিখতে। printf-এ একটা float নিজেই double হয়ে যায়, তাই %f দুইটারই কাজ চালায়; scanf-এ কিছুই বদলায় না, তাই double-র জন্য %lf লাগে।

৩. দুইটা integer ভাগ করে ভগ্নাংশ আশা করা।

int total = 7;
int count = 2;
double average = total / count;
printf("%f\n", average);

কোথাও কোনো message নেই। তুমি আশা করো 3.500000 আর ও ছাপে 3.000000। double উত্তরটা দেখার আগেই ভাগটা পূর্ণসংখ্যার কাজ হিসেবে শেষ হয়ে গেছে। লেখো total / (double)count।

৪. দুইটা দশমিক মান == দিয়ে পরীক্ষা করা।

double sum = 0.1 + 0.2;
printf("%d\n", sum == 0.3);

কোনো message নেই, আর ছাপে 0। মান দুইটা সতেরো নম্বর দশমিক ঘরে আলাদা, আর == সবগুলো ঘর নিয়েই প্রশ্ন করে। বরং একটা পার্থক্যকে epsilon-র সঙ্গে মেলাও।

মাথা খাটাও

Kenji একটা serial number একটা float-এ রাখে, কারণ "এটা একটা সংখ্যা আর float বড় সংখ্যা ধরে"।

#include <stdio.h>

int main(void)
{
    float serial = 16777217.0f;

    printf("%f\n", serial);
    return 0;
}

এটা ছাপে 16777216.000000। মানটা সবচেয়ে বড় float-র অনেক নিচে, আর কিছুই overflow করেনি। শেষ অঙ্কটা কেন হারাল বলো। তারপর কঠিন অংশ: একটা float ধরতে পারে না এমন সবচেয়ে ছোট পূর্ণসংখ্যাটার নাম বলো, আর 16777216 দুই-র ঘাতে কত সেটাও বলো।

একটা float প্রায় 7টা দশমিক অঙ্ক রাখে, মানে প্রায় 24টা binary অঙ্ক। 16777217-র binary অঙ্ক গোনো।

অনুশীলন ১সহজ

Zara গোল টেবিল-mat কাটছে আর প্রতিটার ক্ষেত্রফল দরকার।

Input. এক লাইনে একটা দশমিক সংখ্যা r, সেন্টিমিটারে ব্যাসার্ধ।

Output. এক লাইনে ক্ষেত্রফল, ঠিক দুই দশমিক ঘর পর্যন্ত।

Constraints. 0.01 <= r <= 1000.00। পাই-র জন্য 3.14159265358979 ব্যবহার করো।

Sample. Input 2.5 দিলে 19.63।

#include <stdio.h>

int main(void)
{
    double r = 0.0;
    scanf("%lf", &r);

    /* One printf, with %.2f. */

    return 0;
}

circle-area নামে judge করা হয়। scanf-র %lf-টা ইচ্ছে করেই দেওয়া; ওটাকে %f করলে একসঙ্গে প্রতিটা test ব্যর্থ হয়।

Run in Compiler
অনুশীলন ২মাঝারি

Lesson 1-র অনুশীলন ৩ এবার শেষ করো, এখন যখন জানো ওটা কঠিন ছিল কেন। তিনটা পূর্ণসংখ্যা নম্বর, একটা গড়, দুই দশমিক ঘর।

Input. এক লাইনে তিনটা পূর্ণসংখ্যা a b c।

Output. এক লাইনে ওদের গড়, দুই দশমিক ঘর পর্যন্ত।

Constraints. 0 <= a, b, c <= 100।

Sample. Input 1 1 2 দিলে 1.33।

#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 0;
    int c = 0;
    scanf("%d %d %d", &a, &b, &c);

    /* Change one character of (a + b + c) / 3 and it works. */
    printf("%.2f\n", 0.0);
    return 0;
}

এই module-এ judge করা হয় না। 1 1 2 input দিয়ে / 3 আর / 3.0 দুইটাই চালাও, আর দুইটা output পাশাপাশি রাখো।

Run in Compiler
অনুশীলন ৩মাঝারি

Amara-র আবহাওয়ার পাতায় তাপমাত্রা দুই মাপেই দেখানো হয়। একটা Celsius পাঠকে Fahrenheit-এ বদলাও।

Input. এক লাইনে একটা দশমিক সংখ্যা c।

Output. এক লাইনে Fahrenheit মান, ঠিক এক দশমিক ঘর পর্যন্ত।

Constraints. -100.0 <= c <= 100.0। Fahrenheit হলো c গুণ 9 ভাগ 5, যোগ 32।

Sample. Input 37.0 দিলে 98.6।

#include <stdio.h>

int main(void)
{
    double c = 0.0;
    scanf("%lf", &c);

    /* Write 9.0 and 5.0, not 9 and 5, and say why to yourself. */
    printf("%.1f\n", 0.0);
    return 0;
}

এই module-এ judge করা হয় না। c * 9 / 5 এখানে কাকতালীয়ভাবে কাজ করে, কারণ c আগে থেকেই একটা double। 9 / 5 * c করে না, আর কেন করে না সেটা বের করাই অনুশীলন।

Run in Compiler
অনুশীলন ৪কঠিন

এই lesson যে তুলনাটার পক্ষে যুক্তি দিচ্ছিল, সেটা বানাও। তিনটা দশমিক সংখ্যা পড়ো আর বলো প্রথম দুইটা যোগ করলে তৃতীয়টা হয় কি না।

Input. এক লাইনে তিনটা দশমিক সংখ্যা a b c।

Output. এক লাইনে: a + b যদি c-র 0.000000001-র মধ্যে থাকে তবে 1, নাহলে 0।

Constraints. -1000000 <= a, b, c <= 1000000। একটা লুকানো test হলো 0.1 0.2 0.3, আর সেখানে আশা করা উত্তর 1।

Sample. Input 0.1 0.2 0.3 দিলে 1। Input 1.0 1.0 3.0 দিলে 0।

#include <stdio.h>
#include <math.h>

int main(void)
{
    double a = 0.0;
    double b = 0.0;
    double c = 0.0;
    scanf("%lf %lf %lf", &a, &b, &c);

    /* One printf with %d. A comparison is already a 1 or a 0. */

    return 0;
}

close-enough নামে judge করা হয়। a + b == c লিখলে দ্বিতীয় sample-টা পাশ করে আর প্রথমটা ব্যর্থ হয়, আর সেটাই এই সমস্যার পুরো কথা।

Run in Compiler

যে প্রশ্নগুলো সবার মনে আসে

  • এটা কি C-র একটা bug?

    না। Python, Java, JavaScript আর তোমার phone-র calculator সবাই একই কাজ করে, কারণ সবাই একই IEEE 754 রূপ ব্যবহার করে। C কেবল সেই ভাষা, যেটা তোমাকে ভেতরটা দেখতে দেয়।

  • Epsilon কত হওয়া উচিত?

    1-র আশপাশের সংখ্যার জন্য 1e-9 ভালো একটা শুরু। খুব বড় সংখ্যার ক্ষেত্রে পাশাপাশি দুইটা মানের ফাঁকই বড় হয়ে যায়, তাই নির্দিষ্ট epsilon আর কাজ করে না, তখন আপেক্ষিক পার্থক্য মেলাতে হয়।

  • printf double-র জন্য %f নেয়, অথচ scanf %lf নেয় কেন?

    printf-কে দেওয়া float নিজে থেকেই double হয়ে যায়, তাই একটা specifier দুইটারই কাজ চালায়। scanf একটা address পায় আর ওকে ঠিক কত byte লিখতে হবে বলে দিতে হয়।

  • সবসময় %.2f দিয়ে ছাপলে কি টাকা double-এ রাখা যায়?

    স্কুলের অনুশীলনের জন্য যায়। সত্যিকারের কিছুতে যায় না: অনেকগুলো যোগ পেরিয়ে ভুলগুলো জমতে থাকে, আর একদিন একটা মোট এক পয়সা সরে যায় যেটা কেউ খুঁজে পায় না।

  • কোন দশমিক সংখ্যাগুলো ঠিকঠাক রাখা যায়?

    যেগুলোর ভগ্নাংশ অর্ধেকের যোগফল: 0.5, 0.25, 0.75, 0.125 আর এরকম। একটা double-এ প্রায় 9 কোয়াড্রিলিয়ন পর্যন্ত প্রতিটা পূর্ণসংখ্যাও নিখুঁত।

মূল কথা

  • একটা দশমিক literal সবচেয়ে কাছের binary মান হিসেবে রাখা হয়, যেটা সাধারণত তোমার লেখা মান না।
  • double প্রায় 15 অঙ্ক রাখে আর float প্রায় 7; এই track সব জায়গায় double নেয়।
  • 0.1 + 0.2 == 0.3 হলো 0, আর %.20f-এ ছাপলে কারণটা চোখে দেখা যায়।
  • মেলাও fabs(a - b) < epsilon দিয়ে, কখনো == দিয়ে না।
  • পূর্ণসংখ্যা ভাগ পূর্ণসংখ্যা মানে পূর্ণসংখ্যা, ফলটা যত চওড়া বাক্সেই রাখো।
  • টাকা আর গোনা সবচেয়ে ছোট এককের পূর্ণসংখ্যা; দশমিক মাপার জিনিস।

পরের lesson দুইটা type নিয়ে, যারা সংখ্যা নয় বলে ভান করে, আর একটা তুলনাকে আরেকটা তুলনার সঙ্গে যোগ করা যায় কেন সেটা নিয়ে।

lesson ৩ শেষ

শেষ হলে চিহ্ন দিন, অগ্রগতি আপনার সাথে থাকবে।

পরেরটা: Char, bool, আর যে type-গুলো আসলে সংখ্যা