Gyakorlati alapok
A kör négyszögesítése
Az alcímet könnyen tréfának vehetjük és ilyen célból sokszor talán el is sütöttük, noha a problémával már ógörög matematikusok is szembesültek. Őket elsősorban egy kör területével egyenlő területű négyszög szerkesztésének klasszikusnak mondható, euklideszi lehetősége foglalkoztatta, amely -ha visszaemlékszünk iskolai tanulmányainkból-, körzővel és vonalzóval történik. Ma már tudjuk, hogy ez a probléma euklideszi szerkesztési elvek alapján nem megoldható.
Programozási szempontból a kör négyszögesítése azt az implementációs feladatot dobhatja fel számunkra, miszerint létezik-e azonos területű kör és négyszög?
A matematikában alapszinten jártasak is láthatják a legelső problémát: a körszámításokhoz elengedhetetlenül szükséges PI értéke végtelen, ráadásul nem ismétlődik periodikusan.
Ebből nem jön ki semmi jó, ha kört egy másik, jóval egzaktabb síkidommal hasonlítunk össze, ezért a számítások csakis közelítőek lehetnek. Már csak az a kérdés, hogy mennyire lesznek azok.
Ezt szándékosan mi is erőltethetjük, ha double lebegőpontos pontosság helyett float adattípusra váltunk, ezáltal szűkítjük az eredménypontosságot, remélve, hogy ezzel lesz használható végeredményünk.
A síkidomok területszámító alapképletei a következők, ezt párhuzamosan Java-közeli képlettel is megadhatjuk:
-
Tnegyzet = a2 = pow(a, 2) = a *a
-
Tkor = r2 * PI = pow(r, 2) * Math.PI = (r - r) * 3.14
Könnyű belátni a következőt:
ha kör sugarát 1 egységnek vesszük, akkor 1 egység sugarú kör területe kisebb a köré írt négyzet területénél, ekkor a = 2r...
...√2 egység sugarú kör területe viszont már nagyobb a beleírt négyzet területénél:
Következésképpen a keresett a négyzet-oldalhossz kevéssel 2 alatt lehet. Ezt erősítik a további, négyzettel kapcsolatos képletek:
-
oldalhossz - a = e / √2
-
átló hossza - e = √2 * a
-
beírható kör sugara - r = a / 2 = (√2 * e) / 4
-
köré írható kör sugara - r = (√2 * a) / 2 = e / 2
Az algoritmus egyszerre 2 irányban fog haladni:
-
körterület számítása, ahol a kiindulási pont r = 1, felfelé haladva 0.001 lépésekben, ezért a kezdő körterület = 3.14,
-
négyzetterület számítása, ahol a kiindulási pont a = 2, lefelé haladva 0.001 lépésekben, ezért a kezdő négyzetterület = 4.
Az első végrehajtási mód for ciklus lehet, amelynek léptetését jó nagyra állítjuk. Ha a területek között van egyezés, a ciklusok megállhatnak, sőt abban az esetben is, ha nem volt egyezés, de a körterület már nagyobb négyzetterületnél, hiszen ekkor már nincs értelme a ciklus folytatásának.
Érdekes deklaráció a 3.14f. Magát a 3.14 (mint literált) Java úr alapértelmezésben nem fogja elfogadni, ezért egy f szimbólummal jeleznünk kell számára, hogy lebegőpontos számra gondolunk.
Nézzük meg a futtatható Java-kódot:
public class Main {
public static void main(String[] args) {
float r = 1;
float a = 2;
float területKor = 0;
float területNegyzet = 0;
for(int i = 1; i <= 100; i++){
területKor = (r * r) * 3.14f;
System.out.println(r + " sugár esetén
a körterület: " + területKor);
r += 0.001;
területNegyzet = a * a;
System.out.println(a + " oldalhossz
esetén a négyzetterület: " + területNegyzet);
a -= 0.001;
System.out.println();
if(területKor == területNegyzet){
System.out.println("Egyezés " + területNegyzet + " esetén!");
break;
}
else if(területKor > területNegyzet){
System.out.println("Nincs egyezés!");
break;
}
}
}
}
Végeredmény:
1.0 sugár esetén a körterület: 3.14
2.0 oldalhossz esetén a négyzetterület: 4.0
1.001 sugár esetén a körterület: 3.1462834
1.999 oldalhossz esetén a négyzetterület: 3.9960008
1.0020001 sugár esetén a körterület: 3.1525733
1.9979999 oldalhossz esetén a négyzetterület: 3.9920037
1.0030001 sugár esetén a körterület: 3.1588695
1.9969999 oldalhossz esetén a négyzetterület: 3.9880085
1.0040002 sugár esetén a körterület: 3.1651714
1.9959998 oldalhossz esetén a négyzetterület: 3.9840152
1.0050002 sugár esetén a körterület: 3.1714802
1.9949998 oldalhossz esetén a négyzetterület: 3.980024
1.0060003 sugár esetén a körterület: 3.177795
1.9939997 oldalhossz esetén a négyzetterület: 3.9760349
1.0070003 sugár esetén a körterület: 3.184116
1.9929997 oldalhossz esetén a négyzetterület: 3.9720478
1.0080004 sugár esetén a körterület: 3.1904435
1.9919996 oldalhossz esetén a négyzetterület: 3.9680624
1.0090004 sugár esetén a körterület: 3.1967773
1.9909996 oldalhossz esetén a négyzetterület: 3.9640794
1.0100005 sugár esetén a körterület: 3.2031171
1.9899995 oldalhossz esetén a négyzetterület: 3.960098
1.0110005 sugár esetén a körterület: 3.2094634
1.9889995 oldalhossz esetén a négyzetterület: 3.956119
1.0120006 sugár esetén a körterület: 3.2158158
1.9879994 oldalhossz esetén a négyzetterület: 3.9521418
1.0130006 sugár esetén a körterület: 3.2221746
1.9869994 oldalhossz esetén a négyzetterület: 3.9481666
1.0140007 sugár esetén a körterület: 3.2285397
1.9859993 oldalhossz esetén a négyzetterület: 3.9441934
1.0150007 sugár esetén a körterület: 3.2349112
1.9849993 oldalhossz esetén a négyzetterület: 3.9402223
1.0160007 sugár esetén a körterület: 3.241289
1.9839993 oldalhossz esetén a négyzetterület: 3.936253
1.0170008 sugár esetén a körterület: 3.2476728
1.9829992 oldalhossz esetén a négyzetterület: 3.9322858
1.0180008 sugár esetén a körterület: 3.254063
1.9819992 oldalhossz esetén a négyzetterület: 3.9283206
1.0190009 sugár esetén a körterület: 3.2604594
1.9809991 oldalhossz esetén a négyzetterület: 3.9243574
1.0200009 sugár esetén a körterület: 3.2668622
1.9799991 oldalhossz esetén a négyzetterület: 3.9203963
1.021001 sugár esetén a körterület: 3.2732713
1.978999 oldalhossz esetén a négyzetterület: 3.9164371
1.022001 sugár esetén a körterület: 3.2796862
1.977999 oldalhossz esetén a négyzetterület: 3.9124799
1.0230011 sugár esetén a körterület: 3.286108
1.9769989 oldalhossz esetén a négyzetterület: 3.9085248
1.0240011 sugár esetén a körterület: 3.2925358
1.9759989 oldalhossz esetén a négyzetterület: 3.9045715
1.0250012 sugár esetén a körterület: 3.29897
1.9749988 oldalhossz esetén a négyzetterület: 3.9006205
1.0260012 sugár esetén a körterület: 3.3054104
1.9739988 oldalhossz esetén a négyzetterület: 3.8966713
1.0270013 sugár esetén a körterület: 3.3118575
1.9729987 oldalhossz esetén a négyzetterület: 3.892724
1.0280013 sugár esetén a körterület: 3.3183103
1.9719987 oldalhossz esetén a négyzetterület: 3.888779
1.0290014 sugár esetén a körterület: 3.3247695
1.9709986 oldalhossz esetén a négyzetterület: 3.8848357
1.0300014 sugár esetén a körterület: 3.331235
1.9699986 oldalhossz esetén a négyzetterület: 3.8808944
1.0310014 sugár esetén a körterület: 3.337707
1.9689986 oldalhossz esetén a négyzetterület: 3.8769553
1.0320015 sugár esetén a körterület: 3.3441854
1.9679985 oldalhossz esetén a négyzetterület: 3.873018
1.0330015 sugár esetén a körterület: 3.3506696
1.9669985 oldalhossz esetén a négyzetterület: 3.869083
1.0340016 sugár esetén a körterület: 3.3571603
1.9659984 oldalhossz esetén a négyzetterület: 3.8651497
1.0350016 sugár esetén a körterület: 3.3636572
1.9649984 oldalhossz esetén a négyzetterület: 3.8612187
1.0360017 sugár esetén a körterület: 3.3701606
1.9639983 oldalhossz esetén a négyzetterület: 3.8572893
1.0370017 sugár esetén a körterület: 3.3766701
1.9629983 oldalhossz esetén a négyzetterület: 3.8533623
1.0380018 sugár esetén a körterület: 3.3831856
1.9619982 oldalhossz esetén a négyzetterület: 3.849437
1.0390018 sugár esetén a körterület: 3.3897078
1.9609982 oldalhossz esetén a négyzetterület: 3.8455138
1.0400019 sugár esetén a körterület: 3.3962364
1.9599981 oldalhossz esetén a négyzetterület: 3.8415928
1.0410019 sugár esetén a körterület: 3.4027712
1.9589981 oldalhossz esetén a négyzetterület: 3.8376734
1.042002 sugár esetén a körterület: 3.409312
1.957998 oldalhossz esetén a négyzetterület: 3.8337562
1.043002 sugár esetén a körterület: 3.4158592
1.956998 oldalhossz esetén a négyzetterület: 3.8298411
1.044002 sugár esetén a körterület: 3.4224126
1.955998 oldalhossz esetén a négyzetterület: 3.825928
1.0450021 sugár esetén a körterület: 3.4289725
1.9549979 oldalhossz esetén a négyzetterület: 3.8220167
1.0460021 sugár esetén a körterület: 3.4355385
1.9539979 oldalhossz esetén a négyzetterület: 3.8181076
1.0470022 sugár esetén a körterület: 3.4421108
1.9529978 oldalhossz esetén a négyzetterület: 3.8142004
1.0480022 sugár esetén a körterület: 3.4486895
1.9519978 oldalhossz esetén a négyzetterület: 3.8102953
1.0490023 sugár esetén a körterület: 3.4552743
1.9509977 oldalhossz esetén a négyzetterület: 3.806392
1.0500023 sugár esetén a körterület: 3.4618654
1.9499977 oldalhossz esetén a négyzetterület: 3.802491
1.0510024 sugár esetén a körterület: 3.468463
1.9489976 oldalhossz esetén a négyzetterület: 3.7985916
1.0520024 sugár esetén a körterület: 3.4750667
1.9479976 oldalhossz esetén a négyzetterület: 3.7946944
1.0530025 sugár esetén a körterület: 3.4816768
1.9469975 oldalhossz esetén a négyzetterület: 3.7907994
1.0540025 sugár esetén a körterület: 3.488293
1.9459975 oldalhossz esetén a négyzetterület: 3.7869062
1.0550026 sugár esetén a körterület: 3.4949157
1.9449974 oldalhossz esetén a négyzetterület: 3.783015
1.0560026 sugár esetén a körterület: 3.5015445
1.9439974 oldalhossz esetén a négyzetterület: 3.779126
1.0570027 sugár esetén a körterület: 3.5081797
1.9429973 oldalhossz esetén a négyzetterület: 3.7752388
1.0580027 sugár esetén a körterület: 3.514821
1.9419973 oldalhossz esetén a négyzetterület: 3.7713535
1.0590028 sugár esetén a körterület: 3.5214686
1.9409972 oldalhossz esetén a négyzetterület: 3.7674704
1.0600028 sugár esetén a körterület: 3.528123
1.9399972 oldalhossz esetén a négyzetterület: 3.7635891
1.0610029 sugár esetén a körterület: 3.5347831
1.9389971 oldalhossz esetén a négyzetterület: 3.7597098
1.0620029 sugár esetén a körterület: 3.5414498
1.9379971 oldalhossz esetén a négyzetterület: 3.7558327
1.063003 sugár esetén a körterület: 3.5481222
1.936997 oldalhossz esetén a négyzetterület: 3.7519577
1.064003 sugár esetén a körterület: 3.5548015
1.935997 oldalhossz esetén a négyzetterület: 3.7480843
1.065003 sugár esetén a körterület: 3.561487
1.934997 oldalhossz esetén a négyzetterület: 3.7442133
1.0660031 sugár esetén a körterület: 3.5681784
1.9339969 oldalhossz esetén a négyzetterület: 3.740344
1.0670031 sugár esetén a körterület: 3.5748765
1.9329969 oldalhossz esetén a négyzetterület: 3.736477
1.0680032 sugár esetén a körterület: 3.5815809
1.9319968 oldalhossz esetén a négyzetterület: 3.7326117
1.0690032 sugár esetén a körterület: 3.5882914
1.9309968 oldalhossz esetén a négyzetterület: 3.7287486
1.0700033 sugár esetén a körterület: 3.5950081
1.9299967 oldalhossz esetén a négyzetterület: 3.7248874
1.0710033 sugár esetén a körterület: 3.6017313
1.9289967 oldalhossz esetén a négyzetterület: 3.721028
1.0720034 sugár esetén a körterület: 3.6084607
1.9279966 oldalhossz esetén a négyzetterület: 3.717171
1.0730034 sugár esetén a körterület: 3.6151962
1.9269966 oldalhossz esetén a négyzetterület: 3.713316
1.0740035 sugár esetén a körterület: 3.621938
1.9259965 oldalhossz esetén a négyzetterület: 3.7094626
1.0750035 sugár esetén a körterület: 3.6286862
1.9249965 oldalhossz esetén a négyzetterület: 3.7056115
1.0760036 sugár esetén a körterület: 3.6354408
1.9239964 oldalhossz esetén a négyzetterület: 3.7017624
1.0770036 sugár esetén a körterület: 3.6422017
1.9229964 oldalhossz esetén a négyzetterület: 3.697915
1.0780036 sugár esetén a körterület: 3.6489685
1.9219964 oldalhossz esetén a négyzetterület: 3.69407
1.0790037 sugár esetén a körterület: 3.6557417
1.9209963 oldalhossz esetén a négyzetterület: 3.6902268
1.0800037 sugár esetén a körterület: 3.6625214
1.9199963 oldalhossz esetén a négyzetterület: 3.6863856
1.0810038 sugár esetén a körterület: 3.6693075
1.9189962 oldalhossz esetén a négyzetterület: 3.6825464
1.0820038 sugár esetén a körterület: 3.6760993
1.9179962 oldalhossz esetén a négyzetterület: 3.6787093
1.0830039 sugár esetén a körterület: 3.682898
1.9169961 oldalhossz esetén a négyzetterület: 3.674874
Nincs egyezés!
Ha nem kívánjuk látni a felesleges információkat, ki kell vennünk a köztes System.out.println() metódusokat:
public class Main {
public static void main(String[] args) {
float r = 1;
float a = 2;
float területKor = 0;
float területNegyzet = 0;
for(int i = 1; i <= 100; i++){
területKor = (r * r) * 3.14f;
r += 0.001;
területNegyzet = a * a;
a -= 0.001;
if(területKor == területNegyzet){
System.out.println("Egyezés " + területNegyzet + " esetén!");
break;
}
else if(területKor > területNegyzet){
System.out.println("Nincs egyezés!");
break;
}
}
}
}
Végeredmény:
Nincs egyezés!
Természetesen a ciklusfuttatás más módon, például hátultesztelő ciklussal is elvégezhető. Ebben az esetben azonban le kell kezelnünk a Nincs egyezés! kiírását, legegyszerűbben ezt egy boolean típusú változó (egyezes) segítségével tudjuk szabályozni és megtenni:
public class Main {
public static void main(String[] args) {
float r = 1;
float a = 2;
float területKor = 0;
float területNegyzet = 0;
boolean egyezes;
do{
egyezes = false;
területKor = (r * r) * 3.14f;
r += 0.001;
területNegyzet = a * a;
a -= 0.001;
if(területKor == területNegyzet){
System.out.println("Egyezés " + területNegyzet + " esetén!");
egyezes =
true;
break;
}
}while(területKor < területNegyzet);
if(egyezes == false){
System.out.println("Nincs Egyezés!");
}
}
}
Végeredmény:
Nincs egyezés!
Az előző eredmény lista utolsó sorai pillantva megállapíthatjuk...
...
1.0810038 sugár esetén a körterület: 3.6625214
1.9199963 oldalhossz esetén a négyzetterület: 3.6863856
1.0820038 sugár esetén a körterület: 3.6693075
1.9189962 oldalhossz esetén a négyzetterület: 3.6825464
1.0830039 sugár esetén a körterület: 3.6760993
1.9179962 oldalhossz esetén a négyzetterület: 3.6787093
1.0840039 sugár esetén a körterület: 3.682898
1.9169961 oldalhossz esetén a négyzetterület: 3.674874
. hogy amint az várható volt, még szűkító float adattípus esetén sincs egyezés. Számunkra az utolsó előtti sorpáros a legfontosabb, hiszen itt közelítenek egymáshoz legjobban az eredmények, voltaképpen századpontosságig egyeznek:
1.0830039 sugár esetén a körterület: 3.6760993
1.9179962 oldalhossz esetén a négyzetterület: 3.6787093
Ezek után már csak azt kell tisztáznunk, hogy van-e a Java-rendszerben olyan metódus, amelyik képes kellő mértékben redukálni az éterben lebegő pontosságot?
Az Interneten rákeresve természetesen több metódus is rendelkezésünkre áll. Az egyik nagyon döcögős, voltaképpen a lebegőpontos számból String formátumot gyárt és jó hentes módjára azt vagdossa össze kellő mennyiség szerint:
Forrás - Source: www.stackoverflow.com
public static float onlyTwoDecimalPlaces(String number)
{
StringBuilder sbFloat = new StringBuilder(number);
int start = sbFloat.indexOf(".");
if (start < 0) {
return new Float(sbFloat.toString());
}
int end = start+3;
if((end)>(sbFloat.length()-1)) end = sbFloat.length();
String twoPlaces = sbFloat.substring(start,
end);
sbFloat.replace(start, sbFloat.length(),
twoPlaces);
return new Float(sbFloat.toString());
}
A másik, jóval letisztultabb kóddal sok helyen találkoztam:
float myFloat = 12.349;
myFloat = (float)((int)( myFloat *100f ))/100f;
...és alapműködése miatt nagyon egyszerűen illeszthető a jelen fejezet kódjaiba:
public class Main {
public static void main(String[] args) {
float r = 1;
float a = 2;
float területKor = 0;
float területNegyzet = 0;
for(int i = 1; i <= 100; i++){
területKor = (r * r) * 3.14f;
területKor = (float)((int)(területKor * 100f )) / 100f;
r += 0.001;
területNegyzet = a * a;
területNegyzet
= (float)((int)(területNegyzet * 100f )) / 100f;
System.out.println(a + " oldalhossz
esetén a négyzetterület: " + területNegyzet);
a -= 0.001;
if(területKor == területNegyzet){
System.out.println("Egyezés " + területNegyzet + " esetén!");
break;
}
else if(területKor > területNegyzet){
System.out.println("Nincs egyezés!");
break;
}
}
}
}
Végeredmény:
Egyezés 3.67 esetén!
Nézzünk meg a kerekítésre egy másik metódust is:
double d = 16.66667;
DecimalFormat decimalFormat= new DecimalFormat("#.##");
decimalFormat.setRoundingMode(RoundingMode.FLOOR);
System.out.println("Eredmény: " + decimalFormat.format(d));
import java.math.RoundingMode;
import java.text.DecimalFormat;
public class Main {
public static void main(String[] args) {
double d = 16.66667;
DecimalFormat decimalFormat= new DecimalFormat("#.##");
decimalFormat.setRoundingMode(RoundingMode.FLOOR);
System.out.println("Eredmény: " + decimalFormat.format(d));
}
}
Végeredmény:
Eredmény: 16,66
Ekkor azonban már a double típusokból kapott String értékeket hasonlítjuk össze (if(sztringTeruletKor.equals(sztringTeruletNegyzet)):
import java.math.*;
import java.text.DecimalFormat;
public class Main {
public static void main(String[] args) {
float r = 1;
float a = 2;
double területKor = 0;
double területNegyzet = 0;
for(int i = 1; i <= 100; i++){
DecimalFormat decimalFormat = new
DecimalFormat("#.##");
decimalFormat.setRoundingMode(RoundingMode.FLOOR);
területKor = (r * r) * Math.PI;
String sztringTeruletKor =
decimalFormat.format(területKor);
r += 0.001;
területNegyzet = a * a;
String sztringTeruletNegyzet =
decimalFormat.format(területNegyzet);
a -= 0.001;
if(sztringTeruletKor.equals(sztringTeruletNegyzet)){
System.out.println("Egyezés " + sztringTeruletNegyzet + " esetén!");
break;
}
else if(területKor > területNegyzet){
System.out.println("Nincs egyezés!");
break;
}
}
}
}
Végeredmény:
Egyezés 3.67 esetén!
Mindettől függetlenül most már kijelenthetjük gyanúnkat, miszerint matematikailag nézve területek szempontjából nem lehetséges a kör négyszögesítése. A fenti kódok pusztán programozás-technikailag voltak érdekesek.
Ugyanakkor a kerekítő egyezések során kaptunk egy közelítő 1.9179962 négyzetoldalhosszt is. A területszámító képletek rendezésével...
a2 = r2 * PI
a = r * √PI
...leellenőrizhetjük ezen értéket. 1.0830039 sugár esetén a négyzetoldalhossz megközelítőleg szintén 1.91 körüli lesz.
Házi feladat - Írjuk át a fenti kódot double adattípusra és használjuk fel a Math osztály adatait, metódusait! Változni fog-e a végeredmény?
A megoldás fejezete a képre kattintva érhető el.