Avatar billede hypotroch00id Nybegynder
07. juli 2010 - 11:28 Der er 12 kommentarer og
1 løsning

BigInteger - udskrift af binær repræsentation? - binær ekspansion

Den nye fantastiske BigInteger der følger med .NET 4's  System.Numerics vil ikke spytte binære værdier ud.

Det er tilsyneladende  utroligt nemt i Java men er det mig umuligt at finde ud af i C#.NET
BigInteger tal = whatever;
tal.toString(2);
giver det ønskede udprint fx: 110010000011111110010100000110000

Hvordan overtaler jeg C#.NET  til at gøre noget tilsvarende?
Avatar billede Syska Mester
07. juli 2010 - 12:52 #1
Convert.ToString(1000, 2)

mvh
Avatar billede hypotroch00id Nybegynder
07. juli 2010 - 19:38 #2
tak - men problemet er at 1000 er et meget lille tal - der er angiveligt ikke nogen overloaded metode der understøtter BigIntegers.
BigInteger t = BigInteger.Parse(inputnr.Text);
Convert.ToString(t, 2); //no dice

Jeg har brug for at kende binær form af 1024 bit store tal
Genereret on the fly fra brugerinput, -og anvendes i videre beregninger

Har forsøgt  ting svarende til algoritmer der virker i javascript  som det her:
function printdigits(t){
var digits =[0,1];
for(i=15;i>=0; i--){
document.write(digits[(t>>i)&1]);
}

Men det pangler i C#. De binære operatorer opfører sig ikke helt forudsigeligt...
Avatar billede hypotroch00id Nybegynder
07. juli 2010 - 19:57 #3
Det lykkedes!:
BigInteger t = inputnr.Text;
           
            int len = 4*(inputnr.Text).Length;
            //int[] digits = { 0, 1 };
            string fullnum= " ";
            for (int i = len; i >= 0; i--)
            {
                int inum;
               
                BigInteger num =  (t >> i)&1;
                if(num == 1){
                inum = 1;}
                else if(num == 0){
                inum = 0;}
                else{
                inum=666;
                }
                fullnum =  fullnum  + Convert.ToString(inum);

thank you for watching :)
Avatar billede hypotroch00id Nybegynder
07. juli 2010 - 19:58 #4
tak alligevel :)
Avatar billede arne_v Ekspert
08. juli 2010 - 01:10 #5
fullnum =  fullnum  + Convert.ToString(inum);

skal nok være:

fullnum =  Convert.ToString(inum) + fullnum;

for at give det rigtige resultat.
Avatar billede arne_v Ekspert
08. juli 2010 - 01:12 #6
Men derudover er koden meget dårlig performance mæssigt !

Prøv og kør denne her kode:

using System;
using System.Numerics;
using System.Text;

namespace E
{
    public static class MyExtensions
    {
        public static string Reverse(this string s)
        {
            char[] tmp = s.ToCharArray();
            Array.Reverse(tmp);
            return new string(tmp);
        }
        public static string ToBinaryStringGood(this BigInteger v)
        {
            StringBuilder sb = new StringBuilder();
            foreach(byte b in v.ToByteArray())
            {
                sb.Append(Convert.ToString(b, 2));
            }
            return sb.ToString();
        }
    }
    public class Program
    {
        public static BigInteger Fac(BigInteger n)
        {
              if(n > 1) return n * Fac(n-1); else return 1;
        }
        public static string ToBinaryStringVeryBad(BigInteger v)
        {
            string res = "";
            for(int i = 0; i < v.ToByteArray().Length * 8; i++)
            {
                BigInteger tmp = (v >> i) & 1;
                int n;
                if(tmp == 1)
                {
                        n = 1;
                }
                else if(tmp == 0)
                {
                        n = 0;
                }
                else
                {
                        throw new SystemException("WTF");
                }
                res = Convert.ToString(n) + res;
            }
            return res;
        }
        public static string ToBinaryStringBad(BigInteger v)
        {
              BigInteger v2 = v;   
              StringBuilder res = new StringBuilder();
              while(v2 > 0)
            {
                if(!v2.IsEven)
                {
                        res.Append("1");
                }
                else if(v2.IsEven)
                {
                        res.Append("0");
                }
                else
                {
                        throw new SystemException("WTF");
                }
                v2 >>= 1;
            }
              return res.ToString().Reverse();
        }
        private const int REP = 100;
        public static void Main(string[] args)
        {
            BigInteger v = new BigInteger(10);
            Console.WriteLine(v.ToString());
            Console.WriteLine(ToBinaryStringVeryBad(v));
            Console.WriteLine(ToBinaryStringBad(v));
            Console.WriteLine(v.ToBinaryStringGood());
            BigInteger v2 = Fac(1000);
            DateTime dt1 = DateTime.Now;
            for(int i = 0; i < REP; i++)
            {
                if(ToBinaryStringVeryBad(v2).Length < 1000)
                {
                    throw new Exception("Ooops");
                }
            }
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("Very bad: " + (dt2-dt1).TotalSeconds);
            DateTime dt3 = DateTime.Now;
            for(int i = 0; i < REP; i++)
            {
                if(ToBinaryStringBad(v2).Length < 1000)
                {
                    throw new Exception("Ooops");
                }
            }
            DateTime dt4= DateTime.Now;
            Console.WriteLine("Bad: " + (dt4-dt3).TotalSeconds);
            DateTime dt5 = DateTime.Now;
            for(int i = 0; i < REP; i++)
            {
                if(v2.ToBinaryStringGood().Length < 1000)
                {
                    throw new Exception("Ooops");
                }
            }
            DateTime dt6 = DateTime.Now;
            Console.WriteLine("Good: " + (dt6-dt5).TotalSeconds);
            Console.ReadKey();
        }
    }
}
Avatar billede hypotroch00id Nybegynder
08. juli 2010 - 11:54 #7
@arne_v mange tak :)
Jeg var godt klar over at det var hurtig slamkode der skulle optimeres, men ikke sikker på hvordan det bedst kunne gøres.

Det virker nu efter hensigten. Måske lidt bagvendt at sammensætte oppefra og nem. Men koden giver fx korrekt at 174050332293622031404857552280219410364023488927386650641
giver
01110001100100101011100101011111111111001000110110100111100001100011000100000001000111101101011010110010010011001101110101010111001111111001011101111010000100011110011110010100100000010001. Kontrolleret via Maple.

Men det er ikke altid at man skal leve efter "if-it-works-dont-fix-it" princippet.

Fortrinlige demonstrationseksempler! Endnu en gang tak. Ville gerne give dig point arne_v men det ser ud som om jeg bare har spildt dem på mig selv. (:-O)
Avatar billede hypotroch00id Nybegynder
08. juli 2010 - 11:55 #8
ser at der ikke er ombrydning - så her korrekt binært tal - jf #7

0111000110010010101110010101111111111100100011011010011/
1100001100011000100000001000111101101011010110010010011/
0011011101010101110011111110010111011110100001000111100/
11110010100100000010001
Avatar billede hypotroch00id Nybegynder
08. juli 2010 - 12:41 #9
Nærmere undersøgelse viser at din good algoritme giver det forkerte resultat. Talle behøver ikke være større end 8 bit for at vise det. Indsæt fx
BigInteger v = new BigInteger(256); i stedet for 10.
eller
BigInteger v = BigInteger.Parse("174050332293622031404857552280219410364023488927386650641");

Som jeg ser det må det netop være fordi den blot oversætter hver byte for dig til dens bit værdi i stedet for at se på hele tallets værdi i bit.
Men din 'bad' algoritme er en klar forbedring :) 10 gange så hurtig.
Avatar billede arne_v Ekspert
09. juli 2010 - 02:25 #10
Der var vist lige et par småting der var smuttet i farten.

Men prøv med:

        public static string ToBinaryStringGood(this BigInteger v)
        {
            StringBuilder sb = new StringBuilder();
            byte[] b = v.ToByteArray();
            for(int i = b.Length - 1; i >= 0; i--)
            {
                sb.Append(Convert.ToString(b[i], 2).PadLeft(8, '0'));
            }
            return sb.ToString().TrimStart('0');
        }
    }
Avatar billede arne_v Ekspert
09. juli 2010 - 02:38 #11
Nyt komplet eksempel:

using System;
using System.Numerics;
using System.Text;

namespace E
{
    public static class MyExtensions
    {
        public static string Reverse(this string s)
        {
            char[] tmp = s.ToCharArray();
            Array.Reverse(tmp);
            return new string(tmp);
        }
        public static string ToBinaryStringGood(this BigInteger v)
        {
            StringBuilder sb = new StringBuilder();
            byte[] b = v.ToByteArray();
            for(int i = b.Length - 1; i >= 0; i--)
            {
                sb.Append(Convert.ToString(b[i], 2).PadLeft(8, '0'));
            }
            return sb.ToString().TrimStart('0');
        }
        private static string[] binval = new String[256];
        static MyExtensions() {
            for(int i = 0; i < 256; i++)
            {
                binval[i] = Convert.ToString(i, 2).PadLeft(8, '0');
            }
        }
        public static string ToBinaryStringNotReallyGood(this BigInteger v)
        {
            StringBuilder sb = new StringBuilder();
            byte[] b = v.ToByteArray();
            for(int i = b.Length - 1; i >= 0; i--)
            {
                sb.Append(binval[b[i]]);
            }
            return sb.ToString().TrimStart('0');
        }
    }
    public class Program
    {
        public static BigInteger Fac(BigInteger n)
        {
              if(n > 1) return n * Fac(n-1); else return 1;
        }
        public static string ToBinaryStringVeryBad(BigInteger v)
        {
            string res = "";
            for(int i = 0; i < v.ToByteArray().Length * 8; i++)
            {
                BigInteger tmp = (v >> i) & 1;
                int n;
                if(tmp == 1)
                {
                        n = 1;
                }
                else if(tmp == 0)
                {
                        n = 0;
                }
                else
                {
                        throw new SystemException("WTF");
                }
                res = Convert.ToString(n) + res;
            }
            return res.TrimStart('0');
        }
        public static string ToBinaryStringBad(BigInteger v)
        {
              BigInteger v2 = v;   
              StringBuilder res = new StringBuilder();
              while(v2 > 0)
            {
                if(!v2.IsEven)
                {
                        res.Append("1");
                }
                else if(v2.IsEven)
                {
                        res.Append("0");
                }
                else
                {
                        throw new SystemException("WTF");
                }
                v2 >>= 1;
            }
              return res.ToString().Reverse();
        }
        private const int REP = 100;
        public static void Main(string[] args)
        {
            BigInteger v = new BigInteger(2560);
            Console.WriteLine(v.ToString());
            Console.WriteLine(ToBinaryStringVeryBad(v));
            Console.WriteLine(ToBinaryStringBad(v));
            Console.WriteLine(v.ToBinaryStringGood());
            Console.WriteLine(v.ToBinaryStringNotReallyGood());
            BigInteger v2 = Fac(1000);
            string s1 = ToBinaryStringVeryBad(v2);
            string s2 = ToBinaryStringBad(v2);
            string s3 = v2.ToBinaryStringGood();
            string s4 = v2.ToBinaryStringNotReallyGood();
            if(s1 != s2 || s2 != s3 || s3 != s4)
            {
                throw new Exception("We have a problem");
            }
            DateTime dt1 = DateTime.Now;
            for(int i = 0; i < REP; i++)
            {
                if(ToBinaryStringVeryBad(v2).Length < 1000)
                {
                    throw new Exception("Ooops");
                }
            }
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("Very bad: " + (dt2-dt1).TotalSeconds);
            DateTime dt3 = DateTime.Now;
            for(int i = 0; i < REP; i++)
            {
                if(ToBinaryStringBad(v2).Length < 1000)
                {
                    throw new Exception("Ooops");
                }
            }
            DateTime dt4= DateTime.Now;
            Console.WriteLine("Bad: " + (dt4-dt3).TotalSeconds);
            DateTime dt5 = DateTime.Now;
            for(int i = 0; i < REP; i++)
            {
                if(v2.ToBinaryStringGood().Length < 1000)
                {
                    throw new Exception("Ooops");
                }
            }
            DateTime dt6 = DateTime.Now;
            Console.WriteLine("Good: " + (dt6-dt5).TotalSeconds);
            DateTime dt7 = DateTime.Now;
            for(int i = 0; i < REP; i++)
            {
                if(v2.ToBinaryStringNotReallyGood().Length < 1000)
                {
                    throw new Exception("Ooops");
                }
            }
            DateTime dt8 = DateTime.Now;
            Console.WriteLine("Not really good: " + (dt8-dt7).TotalSeconds);
            Console.ReadKey();
        }
    }
}
Avatar billede hypotroch00id Nybegynder
09. juli 2010 - 17:05 #12
meget nyttigt lille testeksempel :)

Det må være 'binary rightshift' og 'binary and' der tager tiden.
Den kluntede strengopbygning jeg lavede kunne selvfølgelig gøres pænere med stringbuilder, men det synes ikke at bidrage væsentligt til tidsoptimering.
Jeg havde vist ikke læst ordentligt på ToByteArray. Fjollet ikke at benytte de faktiske værdier bare i byte array form - når de nu er lige til at trække ud, frem for at 'genopfinde' tallet som jeg gjorde.
Avatar billede arne_v Ekspert
09. juli 2010 - 19:54 #13
Jeg tror specielt at det er den shift som er dyr.

Proev selv og lav kode som shifter et byte array med 1000 elementer 1 bit. Det bliver en for loekke med 1000 iterationer hvor der i hver iteration skal konstrueres en byte udfra 1 bit fra en byte og 7 bit fra en anden byte.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester