[Çözüldü] c de bir sayının asal çarpanları nasıl bulunur?

Başlatan reflection, 02 Aralık 2011 - 18:34:01

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

reflection

c de girilen bir sayının asal çarpanlarını bulmak için internette birkaç kod buldum; fakat bu kodların hepsinde sadece sayının 2 ile kendisi arasındaki sayılara bölünüp bölünmediği kontrol ediliyor, bölünürse o sayıyı bölünen sayının bir çarpanı olduğunu yazıyor ekrana. fakat benim aradığım sayının sadece asal olan çarpanları (bütün bölenleri değil) ve hangi asal çarpan kaç kez çarpılarak sayı elde edildiği?
örnek vermek gerekirse 120 sayısının 2*2*2*3*5 şeklinde asal çarpanları bulunabiliyor; benim yapmaya çalıştığım da 120 girdisini aldığında 2-2-2-3-5  çıktısını verebilecek bir program. Bu konuda yardımcı olacak birisi var mı acaba?

aşağıda internette bulduğum bir örnek kod var, bu kodda nasıl bir oynama yapılırsa istediğim programı elde ederim?

yardımcı olacak arkadaşlara şimdiden teşekkürler

#include <stdio.h>
     #include <iostream.h>
     
     main()
     {
       
        int a, i, g, no_prime, o=0;
        i = 0;
        g = 0;
        no_prime= 0;
        cout<<"Enter a number:";
        cin>>a;
        cout<<endl<<"The number is "<<a<<endl;
        for (i=2; i<=a; i++)
        {
     
           if (a % i == 0)
           {
          cout << i << " is a factor of " << a << endl;
              ++o;
           }
        }
        if (o == 1)
           cout << "The number " << a <<" is prime\n";
        else
           cout << "The number " << a <<" is not prime\n";
        return 0;
     }


travego0403

#1
Böyle programları modifiye edip istenilen hale getirmektense kendiniz bir algoritma kurup yeniden yazın. Şimdi size istediğiniz işi yapan bir programın kodlarını vereceğim. Umarım bu bir ödev değildir ve bize yaptırmıyorsundur. :)

Bayağı eğlenceli bir soruymuş. Biraz kafa yorduktan sonra biraz da internette araştırayım dedim ve hemen hemen aynı düşündüğüm şeyi buldum. Umarım algoritmasını anlarsınız

#include <iostream>
using namespace std;
int main(int argc, char** argv) {
    int sayi;
    cout<<"Bir sayi giriniz...";
    cin>>sayi;
    int i=2;
    for(i=2;sayi!=1;++i){
        if(sayi%i==0){
            sayi/=i;
            cout<<"Asal Carpan: "<<i<<endl;
            --i;
                       
        }
    }
    return 0;
}
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

reflection

#2
yanıt için çok teşekkürler mantığı çok güzelmiş. yazdığınız kod u 5x4 lük bir array in her bir elemanının sırasıyla asal çarpanlarını bulup bir diğer 5x4 lük arraye de bu asal çarpanların toplamlarını yazdırmak için aşağıdaki şekilde yaptım kod syntax hatası vermiyor fakat ekrana hiçbir şey çıkmıyor. yapmaya çalıştığım şey mesela A[0][0]=6 olsun B[0][0] a 2+3=5 i atayacak
hata yaptığım bir yer varsa yardımcı olur musunuz?


void primefactors ()
{
     int i,j,k,l;
     for( i=0 ; i<5 ; i++);
     {
          for( j=0 ; j<4 ; j++);
          {
               l=A[i][j];
               for(k=2; l!=1; k++)
               {
                   if(l % k==0)
                   {
                       l /= i;
                       B[i][j] += k;
                       --k;           
                    }       
               }
          }
     }   
}

alquirel

l/=i değil l/=k yazacaksınız.
Yanlış değişkeni kullanmışsınız bölme işleminde.

reflection

#4
evet orasını gözden kaçırmışım. söylediğiniz düzeltmeyi yaptım fakat fonksiyon yine herhangi bir çıktı vermiyor  çalıştırdığımda sanırım bir yerden sınırsız döngüye giriyor çünkü işlemci kullanımı % 80 lere çıkıyor.


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 02 Aralık 2011 - 20:49:45

şu an'a kadar yazabildiğim fonksiyonu komple ekliyorum belki başka bir hata yapıyorumdur diye
çalıştırdığımda B array inde alakasız sayılar çıkıyor.

#include <stdio.h>

int main()
{
int A[5][4]= {{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4}};
int B[5][4];
int i,j,k,l;
     for( i=0 ; i<5 ; i++);
     {
          for( j=0 ; j<4 ; j++);
          {
               l=A[i][j];
               for(k=2; l!=1; k++)
               {
                   if(l % k==0)
                   {
                       B[i][j] += k;
                       l /= k;
                       --k;           
                    }       
               }
          }
     }   
     printf("      A\n\n");
     
     for ( i = 0; i < 5; i++ )
     {                                               
      for ( j = 0; j < 4; j++ )                           
         printf( "%2d ", A[ i ][ j ] );                                                                                                                 
          printf( "\n" );       
    }
     printf("\n\n      B\n\n");
     for ( i = 0; i < 5; i++ )
     {                                               
      for ( j = 0; j < 4; j++ )                       
         printf( "%2d ", B[ i ][ j ] );                                                                                                                   
          printf( "\n" );     
    }           
  system("PAUSE");
  return 0;
}

alquirel

#5
Paylaştığınız kod içerisinde bir de iki for parantezinden sonra noktalı virgül yazım hatanız var.
Bu çıktı olmamasını açıklar ama işlemci kullanımının artışını açıklar mı bilmiyorum.

Bir de A'ya ait i ve j noktasındaki değeri alırken B'ye ait i ve j noktasındaki değeri de sıfırlarsanız daha doğru sonuç elde edersiniz.
Yani


l = A[i][j];
B[i][j] = 0;


reflection

dediklerinizi uyguladım fakat programın sonucunda a ve b array inin elemanları ekrana yazdırıldığında b array inin elemanları 6-7 haneli sayılar olarak gözüküyor. hala bir yerde yanlışlık var fakat henüz bulamadım.

alquirel

B dizisinin içindeki değerleri sıfırlama işlemini yapmazsanız böyle olması normal.
Bir değişkeni (global bir şekilde değil de) bir fonksiyonun içinde tanımlarsanız, değişkenin ilk değeri hangi bellek adresi ayrılmışsa oradaki değer olur. Yani alakasız şeyler olur. Bu durumda da ++ işleminiz bu alakasız değer üzerinden gider.

travego0403

Bir kontrol edermisiniz şu şekilde. Gerekli yerleri silin. Debug ederken fazladan değişkenler, çıktılar falan koymuştum.

#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, char** argv) {
        int sayi;
        int toplam=0;
        int i=2;
        int j,k;    // Döngü değişkenleri
        int A[5][4]={{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4},{1,2,3,4}};
        int B[5][4]={{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
        for(j=0;j<5;++j){
                for(k=0;k<4;++k){
                        sayi=A[j][k];
                        toplam=0;
                        for(i=2;sayi!=1;++i){
                                if(sayi%i==0){
                                        sayi/=i;
                                        cout<<"Asal Carpan: "<<i<<" ";
                                        toplam+=i;
                                        --i;
                                }                   
                        }
                        cout<<endl;
                        B[j][k]=toplam;
                }
        }
        printf("      A\n\n");
        for ( i = 0; i < 5; i++ ){
                for ( j = 0; j < 4; j++ ) 
                        printf( "%2d ", A[ i ][ j ] );                                                                                                                 
                printf( "\n" );       
        }
        printf("\n\n      B\n\n");
        for ( i = 0; i < 5; i++ ){   
                for ( j = 0; j < 4; j++ )                       
                        printf( "%2d ", B[ i ][ j ] );                                                                                                                   
                printf( "\n" );     
        }           
return 0;
}
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

reflection

verdiğiniz kod sorunsuz çalıştı.
kodunuzun tam olarak C ye uyarlanmış halini de ekliyim buraya başkalarına da yardımcı olması için.

programa ekleme yapmayı düşündüğüm bir kaç kısım daha var onları da kesinleştirebilirsem tekrar fikir almak için buraya yazarım
şu ana kadar yardımı olan herkese teşekkürler.

#include <stdio.h>
int main() {
        int sayi;
        int toplam=0;
        int i=2;
        int j,k;    // Döngü değişkenleri
        int A[5][4]={{5,2,3,4},{7,2,3,4},{8,2,3,4},{1,2,3,4},{1,2,3,4}};
        int B[5][4]={{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
        for(j=0;j<5;++j){
                for(k=0;k<4;++k){
                        sayi=A[j][k];
                        toplam=0;
                        for(i=2;sayi!=1;++i){
                                if(sayi%i==0){
                                        sayi/=i;
                                        printf("Asal Carpan: %d ",i);
                                        toplam+=i;
                                        --i;
                                }                   
                        }
                        printf( "\n" );
                        B[j][k]=toplam;
                }
        }
        printf("      A\n\n");
        for ( i = 0; i < 5; i++ ){
                for ( j = 0; j < 4; j++ ) 
                        printf( "%2d ", A[ i ][ j ] );                                                                                                                 
                printf( "\n" );       
        }
        printf("\n\n      B\n\n");
        for ( i = 0; i < 5; i++ ){   
                for ( j = 0; j < 4; j++ )                       
                        printf( "%2d ", B[ i ][ j ] );                                                                                                                   
                printf( "\n" );     
        }           
system("PAUSE");
return 0;
}

alquirel

Alıntı yapılan: reflection - 03 Aralık 2011 - 00:28:46
programa ekleme yapmayı düşündüğüm bir kaç kısım daha var onları da kesinleştirebilirsem tekrar fikir almak için buraya yazarım

Normalde başlıktaki sorunun cevabını buldunuz ancak burayı referans alarak başlığı açık tutuyorum. ;)

travego0403

Gece iyi idman olmuştu bana sonsuz döngüye girdiği yeri bulmak. :) Bütün döngülerin daha birinci turunda sonsuz döngüye giriyor ve sürekli 2 sayısı ile topluyordu. Debugger(fazlada anlamam ya) falan kullanarak baktım ama bellek hatası olmadığı için tam yerini bulamadım. Değişkenlerin değerlerini inceledim sanki biraz anlar gibi oldum. Koda dönüp baktığımda 3.for döngüsünde döngünün başlangıç şartının hatalı olduğunu gördüm. Başka bir yerini de düzelttim mi bilmiyorum kafam biraz dalgın bu aralar. :)

Bence, bütün bu programı yazarken hata yapmanız değişkenleri isimlendirmemeniz yüzünden. Çünkü i,j,k,l gibi ne olduğu belirsiz değişken isimleri kullanmışsınız. Size tavsiyem değişkenlerin isimlerini anlayabileceğiniz şekilde açık olarak yazmanızdır. i,j,k gibi isimler genellikle döngü değişkenleri olarak kullanılır. Herhangi bir değeri tutmak için kullandığınız değişkenin ismini içeriğiyle alakalı olarak veriniz. ;)
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

reflection

#12
Alıntı yapılan: alquirel - 03 Aralık 2011 - 10:56:13
Normalde başlıktaki sorunun cevabını buldunuz ancak burayı referans alarak başlığı açık tutuyorum. ;)
teşekkürler

Alıntı yapılan: travego0403 - 03 Aralık 2011 - 12:21:52
Bence, bütün bu programı yazarken hata yapmanız değişkenleri isimlendirmemeniz yüzünden. Çünkü i,j,k,l gibi ne olduğu belirsiz değişken isimleri kullanmışsınız. Size tavsiyem değişkenlerin isimlerini anlayabileceğiniz şekilde açık olarak yazmanızdır. i,j,k gibi isimler genellikle döngü değişkenleri olarak kullanılır. Herhangi bir değeri tutmak için kullandığınız değişkenin ismini içeriğiyle alakalı olarak veriniz. ;)
evet dediğinizde haklısınız daha önce başkalarıda aynı tavsiyeyi vermişti fakat bir türlü ilk alışkanlığı yenemedim. adlandırmaları düzgün yapmadığımdan sürekli değişkenlerde hata çıkıyor. inş. tavsiyenizi yakın zamanda uygulamaya geçirebileceğim  :D



Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 03 Aralık 2011 - 23:16:15

bir sorum daha olacak. yukarda main fonksiyonunun içinde tanımladığım A array ini programdaki başka bir fonksiyondan nasıl çağırabilirim? (A array ini main fonksiyonunu açmadan tanımlarsam bu iş oluyor fakat o zaman bütün program fonksiyonlarında A array i tanımlanmış oluyor. ben sadece bir fonksiyona aktarmak istiyorum A array ini.)
arraylerin de birer pointer olduğunu düşünüp ilk elemanın adresini, A arrayini çağırmak istediğim fonksiyona referans versem olur diye düşündüm. sonrada adres değerini 1 er 1 er arttırarak diğer elemanları yazdırmayıdüşünüyordum fakat A 5*4 biçiminde olduğundan adres değerlerinde kafam allak bullak oldu.
bunun daha pratik bir yolu varmıdır acaba?

travego0403

#13
Al bakalım matrislerin fonksiyonlara nasıl argüman olarak aktarılacağı. :) Yeteri kadar örnek olmuştur sanırsam. Ekrana yazması için bir fonksiyon yazdım kod tekrarından kurtarır hem. Ayrıca matrisin içinide nasıl sıfırlanacağınıda bir fonksiyon yardımıyla gösterdim. Çıktıları düzenlemeyi unutma şu an göze pek hoş gelmiyorda. :)

Ek: şimdi aklıma geldi. 3.döngüde yaptığımız asal çarpan bulma içinde bir fonksiyon yazarsan kodun okunabilirliği dahada artar. Matrisin elemanları bu fonksiyona tek tek geçilir ve fonksiyondan dönen değerde tekrar B matrisinin ilgili elemanına atanabilir.

#include <stdio.h>
void sifirla(int b[][4]);
void ekranaYaz(int b[][4]);
int main() {
        int sayi;
        int toplam=0;
        int i=2;
        int j,k;    // Döngü değişkenleri
        int A[5][4]={{5,2,3,4},{7,2,3,4},{8,2,3,4},{1,2,3,4},{1,2,3,4}};
        int B[5][4];
        printf("Islemden once\n");
        printf("*******************************\n");
        sifirla(B);       
        ekranaYaz(A);
        printf("\n \n");
        ekranaYaz(B);
        for(j=0;j<5;++j){
                for(k=0;k<4;++k){
                        sayi=A[j][k];
                        toplam=0;
                        for(i=2;sayi!=1;++i){
                                if(sayi%i==0){
                                        sayi/=i;
                                        printf("Asal Carpan: %d ",i);
                                        toplam+=i;
                                        --i;
                                }                   
                        }
                        printf( "\n" );
                        B[j][k]=toplam;
                }
        }
        printf("*******************************\n");
        printf("Islemden sonra\n");
        printf("*******************************\n");
        printf("      A\n\n");
        ekranaYaz(A);
        printf("      B\n\n");
        ekranaYaz(B);
                 
//system("PAUSE");
return 0;
}

void sifirla(int b[][4]){
    for(int i=0;i<5;++i){
        for(int j=0;j<4;++j)
            b[i][j]=0;
    }
}

void ekranaYaz(int b[][4]){
        for (int i = 0; i < 5; i++ ){   
                for (int j = 0; j < 4; j++ )                       
                        printf( "%2d ", b[ i ][ j ] );                                                                                                                     
                printf( "\n" );     
        } 
   
}
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

reflection

Alıntı yapılan: travego0403 - 03 Aralık 2011 - 23:53:52
Ek: şimdi aklıma geldi. 3.döngüde yaptığımız asal çarpan bulma içinde bir fonksiyon yazarsan kodun okunabilirliği dahada artar. Matrisin elemanları bu fonksiyona tek tek geçilir ve fonksiyondan dönen değerde tekrar B matrisinin ilgili elemanına atanabilir.
bende onu yapmaya çalışıyordum zaten asal çarpanları bulmak için bir fonksiyon matrisleri ekrana yazdırmak için bir fonksiyon tanımladım ama aralarındaki matris aktarımını beceremedim. Yazdığınız kod u yarın erkenden inceliyip buraya sonucu yazacağım (bu saatte düzgün bir şey yapabileceğimi sanmıyorum :D )

microanaliz

#include<stdio.h>
int main()
{
    int a,b,c,d,e,f,g,l,m,n;
    printf("Bir sayı girin asal olup olmadığını söyleyelim\n");
    scanf("%d",&n);

a=n%2;
b=n%3;
c=n%4;
d=n%5;
e=n%6;
f=n%7;
g=n%8;
l=n%9;
m=n%10;
if(n==2||n==3||n==5||n==7)
    printf("Sayınız asal sayıdır");
else if(a>=1&&b>=1&&c>=1&&d>=1&&e>=1&&f>=1&&g>=1&&l>=1&&m>=1)
printf("Sayınız asal sayıdır");
else
printf("Sayınız asal değil");
return 0;
}

Sayınızı girin asal olup olmadığını söyleyen bir program parçası bir fikir...
MicroAnaliz

alquirel

@microanaliz,

Asal sayı bulmak uğruna gördüğüm en amatör kodu yazmışsın diyebilirim. Niçin mi?
  • Bir sayı 8'e bölünüyorsa 4'e zaten bölünür, 2'ye haydi haydi bölünür, 9'a bölünüyorsa da 3'e zaten bölünür. Aynı şekilde 6 ve 10 da gereksiz.
  • Senin kodun daha yolun başında patlak verecek, çünkü senin yazdığın koda göre 121 sayısı asal çıkıyor, halbuki kendisi 11'in karesi...
  • Bunları sana faydalı olabilmek için yazıyorum. Asal sayı bulan kod için ilk iletiye bakabilirsin.

@reflection,

Evet array değişkenleri işaretçidir esasında. Ama ikili üçlü ... olması seni yanıltmasın. Mesela sen 5x4'lük bir array tanımladığında bellekten sıra ile 20 adet birim ayrılır. Diyelim ki sen 11. öğeye ulaşacaksın (yani tekli array olsaydı A[10] olacaktı). Köşeli parantezle yapmak istersen A[2][2] yazacaksın. Ama bunlar bellekte sıra ile ayrıldığı için bu, A[10] yazmakla aynı şeyi ifade eder. İşaretçi şeklinde düşünürsek de A[2][2] için A+10 ifadesini çok rahatlıkla kullanabilirsin.

reflection

@travego0403, yazdığınız koddaki gibi array i fonksiyona göndermeyi başardım. hatta beklediğimden daha kolaymış diyebilirim.

@alquirel, 20 birimim sıra ile olduğunu öğrenmem aşağıda yapmaya çalıştığım fonksiyonun temel mantığını oluşturdu fakat tam olarak altından kalkamadım diyebilim.

bu başlıktaki son soruyu soruyorum. yapmaya çalıştığım programın iskeletini tamamladım diyebilirim (sizin yardımınızla tabiki :D )

A array inin elemanlarını x'e bağlı bir fonksiyon ile tanımlamak istiyorum.
x burada elemanın arraydaki sırasını temsil edicek. mesela  A[1][1] e koyulacak değeri bulmak için fonksiyonda x yerine 1 koyulacak A[1][2] için x=2 vs.

array tek boyuttan oluşsa bu işlemi basit bir for döngüsüyle hallederdim fakat  2. ,3. ,4. ve 5. satırlara geçişte x değerini kaldığı yerden nasıl devam ettireceğimi bulamadım.
yani 5x4 lük array de A[1][4] için x=4 ise A[2][1] de x=5 olarak fonksiyona girecek  ve sonucu matrisin o kısmına kaydedilecek.

aşağıdaki gibi bir kod ile adres bölgeleri üzerinden işlem yapmayı denedim ama derleme sırasında bir sürü hata aldım sanırım kurduğum mantıkta bir yanlışlık var.

void arrayolusturma ();
{
    int A[5][4];
    int x,n=0;
    for(x=1,x<=20,x++)
    {
          *(A+n)= F(x); // F (x)  daha sonra herhangi bir fonksiyonla değiştirilecek
          n++;
    }

}

travego0403

#18
Çok basit. Döngü değişkenlerini ve sırayı sayacak olan değişkeni ayıracaksın. :) i ve j döngü değişkenleri ise sayac adlı bir değişken daha ekle. Bu değişken hiç sıfırlanmadan sürekli birer birer veya ne kadar lazımsa artsın. Eğer anlamazsan örnek kodu verebilirim.

Problemleri kendi kendide zorlaştırıyorsun. Adreslerle uğraşmayı bırak şimdilik. :) Bir programı hiç pointer kullanmadan da yapabilirsin. Pointer kullanmak yerine göre programa hız kazandırabilir fakat böyle küçük örneklerde gözle görülen bir değişikliğe yol açmaz. Aslında soruların çözümleri basit. Zor olan basit çözümü düşünmek. Sözün orijinali: "Futbol basit oyundur, zor olan basit oynamak." Ünlü bir futbol adamına aitti ismini şu an hatırlamıyorum.


Ek: @microanaliz İlk iletideki örnek asal sayıları bulan bir örnek ama hala üzerinde en iyileştirme(optimizasyon) yapılmamıştır.(Aslında programın asıl amacı bölenlerini bulmak) Çünkü sayıyı 2 den başlayarak kendine kadar olan bütün sayılara bölerek denemek gereksizdir. Yarısına kadar ya da 1/3(?)'e kadar denense yeterlidir. Ayrıca sayı çiftse h,ç uğraşmadan asal değildir deyip çıkılabilir.
"Matematik bir dildir ve bu dilde şairlere fizikçi denir." Richard Feynman

reflection

sayaçla sorun halloldu. sonradan pointer la nerde yanlış yaptığıma bakarken for döngüsünde ayıraç olarak (;) yerine (,) kullandığımı farkettim  :D  kafa iyice gitti sonunda ama olsun programın iskeleti tamamlandı.

fonksiyon kısmı aşağıdaki gibi olunca çalışıyor

    int A[5][4];
    int x=1;
    for(j=0;j<5;++j)
    {
          for(k=0;k<4;++k)
          {
           A[j][k] = x; // x yerine istenilen fonksiyon konulabilir
           x++;
           }             
    }


başlık görevini yerine getirmiştir yardımcı olan herkese çok teşekkürler.

alquirel

Bir meseleye daha cevap verip konuyu kilitleyeyim.

@travego0403, aslında sayıyı yarısına veya 1/3'üne kadar böldürmek içeride ekstra bölen bırakabilir, veya dışarıda kalan bölenler olabilir. İstisnasız tüm ihtimalleri kapsayan ve sadece bir kez deneyen tek değer sayının kareköküdür. For döngüsüne yazarken de sqrt fonksiyonu yeterli olur, sayının tam kare olmasına gerek kalmaz.

Alıntı yapılan: reflection - 04 Aralık 2011 - 11:52:04
başlık görevini yerine getirmiştir yardımcı olan herkese çok teşekkürler.

Burayı referans alarak kilitliyorum. Çözülen konularda ilk iletimizin başlığına [Çözüldü] ifadesi eklerseniz müteşekkir oluruz ;)