Avatar billede Slettet bruger
27. oktober 2008 - 22:29 Der er 108 kommentarer og
1 løsning

Type med plads til meget store og præcise tal

Hej eksperter,

Hvilke typer kan jeg anvende, hvis jeg vil regne på meget store og præcise tal? F.eks. en gogool eller en værdi med en trillion decimaler.
Avatar billede arne_v Ekspert
27. oktober 2008 - 23:42 #1
Find en biginteger eller bigfloat pakke.
Avatar billede arne_v Ekspert
27. oktober 2008 - 23:43 #2
En mulighed er at bruge Java BigInteger & BigDecimal fordi .NET framework indeholder
Java API for Java 1.1 p.g.a. J#.
Avatar billede Slettet bruger
27. oktober 2008 - 23:45 #3
Mange tak :) Jeg kikker lige på det, når jeg kan holde hovedet oppe uden fyrre liter cola og en stak bøger. Læs: Jeg er træt!
Avatar billede arne_v Ekspert
27. oktober 2008 - 23:46 #4
Men ellers kan du google.

http://www.codeproject.com/KB/cs/biginteger.aspx

er en af dem som dukekr op.
Avatar billede Slettet bruger
29. oktober 2008 - 09:20 #5
Så mangler jeg bare at finde en til decimaler... Kan jeg hente BigDecimal et sted? Google finder en masse Java-høvl, når jeg søger på 'bigdecimal c#'.
Avatar billede arne_v Ekspert
30. oktober 2008 - 01:16 #6
Hm. Jeg kan godt nok heller ikke lige opgoogle noget.

Så:
- brug java.math.BigDecimal
- lav dit eget ved hjælp af BigInteger
Avatar billede Slettet bruger
30. oktober 2008 - 08:22 #7
Skønt! Jeg prøver lige... Bare smid et svar i mellemtiden.
Avatar billede Slettet bruger
30. oktober 2008 - 08:54 #8
Pokkert... Hvordan kommer jeg til at bruge java.math? Med 'using' eller...?
Avatar billede arne_v Ekspert
30. oktober 2008 - 14:02 #9
using java.math;

og

ref til vjslib.dll
Avatar billede Slettet bruger
30. oktober 2008 - 18:50 #10
Den forstod jeg ikke...
VC# genkender ikke java i 'using java', og jeg kan ikke finde vjslib.dll på nogen lister, når jeg vælger at tilføje en reference (hvis det er det, jeg skal) - kan du forklare, hvad der er, jeg har misforstået?
Uh, jeg er godt nok lidt af en programmeringsrookie.
Avatar billede arne_v Ekspert
30. oktober 2008 - 19:05 #11
Du kan foerst lave den using, naar du har en ref til vjslib.dll - hvis du ikke har den
skal du nok have fat paa:

http://www.microsoft.com/downloads/details.aspx?familyid=f72c74b3-ed0e-4af8-ae63-2f0e42501be1&displaylang=en
Avatar billede Slettet bruger
30. oktober 2008 - 21:00 #12
ARGH! Det var god grænseløst irriterende!
Eksperten er begyndt at slette mine meddelelser - når jeg poster dem, kommer der intet frem i tråden, og tekstboksen bliver tømt.

Anyway, here we go again:

Et par spørgsmål:
1) Hvordan konverterer jeg lettest standardklasser til BigInteger eller BigDecimal? Jeg har leget med 'new BigInteger(n)', hvor n f.eks. er short/int/long - det virker men er meget besværligt.
2) Jeg får fejl ved operatorer som '<' og '+=' mellem BigIntegers... Hvorfor?
Avatar billede arne_v Ekspert
30. oktober 2008 - 21:16 #13
De har en constructor som tager String.

Java har ikke operator overload, saa man skal bruge metoder !
Avatar billede Slettet bruger
30. oktober 2008 - 22:12 #14
1) Jeg mener, hvis jeg har en int, som jeg skal bruge som BigInteger, hvordan gør jeg så?

2) Det var pokkers... Ikke særlig praktisk!
Avatar billede arne_v Ekspert
30. oktober 2008 - 23:41 #15
re 1)

Du kan bruge den static metode valueOf til at konvertere en int til BigInteger.

re 2)

Generelt savner folk ikke operator overload i Java. Men lige netop BigInteger og BigDecimal
brokker folk sig rigtigt meget, fordi det er en PITA.
Avatar billede Slettet bruger
30. oktober 2008 - 23:50 #16
Hm, ja, jeg vænner mig nok til det... Tak for hjælpen!
Avatar billede Slettet bruger
31. oktober 2008 - 23:10 #17
NEJ!
Endnu engang har Eksperten ikke postet min kommentar, og denne gang opdagede jeg det ikke... Yderst frustrerende!

Anyway. Hvordan kan jeg opløfte BigIntegers og BigDecimals i potenser? Jeg har googlet mig frem til pow(int), men denne metode genkendes ikke af VC#.
Avatar billede arne_v Ekspert
01. november 2008 - 01:46 #18
pow er i Java 1.5 men J# implementerer (det meste af) Java 1.1

så du må multiplicere manuelt
Avatar billede Slettet bruger
01. november 2008 - 01:57 #19
Tak og undskyld, jeg lige flamede Eksperten - for det var denne gang mig, der postede der forkerte sted... Hvilket du forhåbentligt opdagede :)
Jeg må prøve med en løkke og multiplikation.
Avatar billede Slettet bruger
02. november 2008 - 18:20 #20
Jeg har et (nyt) problem!

"pow er i Java 1.5 men J# implementerer (det meste af) Java 1.1
så du må multiplicere manuelt"

Det gik også fint i et stykke tid - men nu har jeg bemærket, at jeg skal opløfte en værdi i et ulige tal. Hvordan kan jeg manuelt gøre dette, og er der virkelig slet ingen mulighed for at anvende en eksisterende pow-metode?
Avatar billede arne_v Ekspert
02. november 2008 - 19:19 #21
Det er vel ligegyldigt om det er ulige ??

        public static BigDecimal pow(this BigDecimal x, int n)
        {
            if (n == 0)
            {
                return new BigDecimal("1.0");
            }
            else if (n == 1)
            {
                return x;
            }
            else
            {
                int nhalf = n / 2;
                return x.pow(nhalf).multiply(x.pow(n - nhalf));
            }
        }
    }
Avatar billede arne_v Ekspert
02. november 2008 - 19:20 #22
hov jeg manglere 2 linier:

    public static class NewerJavaEmulation
    {
        public static BigDecimal pow(this BigDecimal x, int n)
        {
            if (n == 0)
            {
                return new BigDecimal("1.0");
            }
            else if (n == 1)
            {
                return x;
            }
            else
            {
                int nhalf = n / 2;
                return x.pow(nhalf).multiply(x.pow(n - nhalf));
            }
        }
    }
Avatar billede Slettet bruger
02. november 2008 - 19:37 #23
Jamen, hvor får du BigDecimal.pow fra?
> return x.pow(nhalf).multiply(x.pow(n - nhalf));
Det er vel hele problemet, at den metode ikke findes.
Avatar billede arne_v Ekspert
02. november 2008 - 19:44 #24
Den har jeg jo selv lavet (det er et rekursivt kald !).
Avatar billede arne_v Ekspert
02. november 2008 - 19:44 #25
Jeg har tilladt mig at bruge .NET 3.5 / C# 3.0 extension metode.

Hvis du er på 2.0 skal det laves lidt mere simpelt.
Avatar billede Slettet bruger
02. november 2008 - 20:49 #26
I don't get it. Jeg fårstår koden, ja, men hvorfor er matematikken rigtig?
Avatar billede arne_v Ekspert
02. november 2008 - 21:10 #27
generelt er

x.pow(a+b) = x.pow(a)*x.pow(b)

derfor er:

x.pow(n) = x.pow(n/2)*x.pow(n-n/2)
Avatar billede Slettet bruger
03. november 2008 - 07:33 #28
Uha, ja, det er godt at kunne sin matematik :P
Mange tak... Jeg roder videre med det!
Avatar billede Slettet bruger
25. november 2008 - 15:57 #29
Hm. Jeg har forsøgt at lave en enklede Chudnovsky-algoritme med C#'s indbyggede klasser...


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PiTestChudnovsky
{
    class SimpleChudnovsky
    {
        public long Ticks = 0;
        public long Precision = 0;
        public double Result;

        public SimpleChudnovsky(long n)
        {
            Calculate(n);
        }

        public double Calculate(long n)
        {
            long ticks = DateTime.Now.Ticks;
            Precision = n;
            double result = 0;
            for (long k = 0; k <= n; k++)
                result += Math.Pow((double)-1, (double)k) * (double)SimpleMath.Faculty(6 * k) * (double)(13591409 + 545140134 * k) / (double)SimpleMath.Faculty(3 * k) / Math.Pow((double)SimpleMath.Faculty(k), (double)3) / Math.Pow((double)640320, (double)(3 * k) + (double)3 / (double)2);
            Result = 1 / (12 * result);
            Ticks = DateTime.Now.Ticks - ticks;
            Console.WriteLine(":" + Result.ToString() + ":");
            return Result;
        }
    }
}


Problemet er bare, at applikationen udskriver :NaN: ved kald! Hvorfor?
Avatar billede Slettet bruger
25. november 2008 - 15:58 #30
Og for lige at hjælpe C# lidt på vej:
Result = (double)1 / ((double)12 * result);
i stedet for
Result = 1 / (12 * result);
Men det gør ingen forskel for NaN-problemet :(
Avatar billede arne_v Ekspert
26. november 2008 - 04:24 #31
Den virker for n=3 for mig - derefter overflower min long baserede Faculty.
Avatar billede Slettet bruger
26. november 2008 - 08:16 #32
Ved n=3 skriver min stadig NaN (jeg testede tidligere med n=1)...
Du får lige hele koden:


Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using java.math;

namespace PiTestChudnovsky
{
    class Program
    {
        static void Main(string[] arguments)
        {
            SimpleChudnovsky myPi = new SimpleChudnovsky(3);
            Console.WriteLine("::: " + myPi.Result.ToString() + " :::");
            Console.ReadKey(true);
        }
    }
}


SimpleMath.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PiTestChudnovsky
{
    class SimpleMath
    {
        public static long Faculty(long n)
        {
            for (long i = n; i > 1; n *= --i) { };
            return n;
        }
    }
}


Og SimpleChudnovsky.cs indeholder koden opgiver her tidligere.
Avatar billede Slettet bruger
26. november 2008 - 19:27 #33
Får I ingen fejl med den kode?
Avatar billede arne_v Ekspert
26. november 2008 - 21:27 #34
Prøv med:

        public static long Faculty(long n)
        {
            if (n==0) return 1;
            for (long i = n; i > 1; n *= --i) { };
            return n;
        }
Avatar billede Slettet bruger
26. november 2008 - 23:02 #35
Hvad pokker! Jeg havde ingen anelse om, at fakultet 0 giver 1... Kan jeg få dig til at give en matematisk forklaring (hvis den ikke er for omfattende)?
PS: Det virker nu :)

Og så har jeg lige et andet spørgsmål samtidig: Samtlige beregninger af antal ticks forløbet under beregninger giver 0. Hvorfor? Jeg har også prøvet med Environment.TickCount (også uden held).
Avatar billede arne_v Ekspert
26. november 2008 - 23:08 #36
Der er en halv forklaring på http://en.wikipedia.org/wiki/Factorial
Avatar billede Slettet bruger
26. november 2008 - 23:11 #37
Suk. Wikipedia har en tendens til at gøre matematik besværligt og samtidig alt for enkelt... Måske skulle jeg bare spørge min matematiklærer engang :)
Anyway, det andet spørgsmål er vigtigere.
Avatar billede arne_v Ekspert
26. november 2008 - 23:14 #38
3 iterationer tager simpelthen ingen tid.

Ticks bliver ikke talt op en af gangen.

Så du skal udføre noget mere for at du kan måle det.

Du kan evt. lave det samme 1000 gange og så måle det og dividere med 1000.
Avatar billede arne_v Ekspert
26. november 2008 - 23:15 #39
Argumentet er at:

n! = n * (n-1)!

hvis n=1 så står der:

1! = 1 * 0!

for at det er sandt så skal 0! være 1 ...
Avatar billede Slettet bruger
26. november 2008 - 23:42 #40
Jeg bliver simpelhen nødt til at smutte i seng nu. Tak for svarerne - jeg kikker på det i morgen (promise!).
Avatar billede arne_v Ekspert
26. november 2008 - 23:44 #41
Nu er vi nogen som har helligdag imorgen !

:-)
Avatar billede Slettet bruger
27. november 2008 - 13:04 #42
OFFTOPIC: Hvilken helligdag og hvad betyder den for Eksperten? Bare nysgerrig...

Jeg synes godt nok, fakultetsargumentet virker konstrueret og desperat men skidt med det.

Du har ret; ticks virker over 500-1000 itterationer.

Dog er der noget, der undrer mig: Fra og med n=23 giver resultatet NaN - skyldes det de meget høje tal, eller har jeg fucket noget op?
Avatar billede arne_v Ekspert
27. november 2008 - 14:53 #43
Thanksgiving

(jeg bor ikke i Danmark)
Avatar billede arne_v Ekspert
27. november 2008 - 14:55 #44
Det lyder meget sandsynligt at dine NaN skyldes for høje tal.

Men men men.

Muligvis har du problemer allerede før det.

Jeg fik problemer allerede med n=4.

Jeg oversatte nemlig koden med check for integer overflow.

Jeg synes at du skulel prøve og slå det til !
Avatar billede Slettet bruger
27. november 2008 - 15:01 #45
Aha :) Jamen glædelig Thanksgiving!

Hvordan tjekker jeg integer overflow?

PS: Projektet begynder i morgen, så jeg skal snart til at kode med de stpre klasser - jeg vil dog gerne anvende nogle lidt bedre integrerede end BigInteger og BigDecimal fra Java, så kender du nogle oplagte alternativer?
Avatar billede arne_v Ekspert
27. november 2008 - 15:15 #46
Det er en compiler option.

/checked+

Bruger du VS kan du sætte et flueben et eller andet sted.
Avatar billede arne_v Ekspert
27. november 2008 - 15:17 #47
Vi fandt jo en .NET big integer klasse en 25 indlæg siden, men det var et problem
at finde en big float klasse.
Avatar billede Slettet bruger
27. november 2008 - 17:40 #48
Hmm... Jeg har nu forsøgt at slå samtlige debugging-exceptions til - men jeg fik ingen runtime-fejl. Jeg tror, jeg lader det ligge og kikker på det, hvis problemet genopstår med de nye talklasser.

Jeps, jeg kan godt huske BigInteger-klassen, men jeg håbede, at du var faldet over et alternativ til BigDecimal... Eller at en anden havde en god BigFloat til at ligge.
Jeg leder videre!
Avatar billede arne_v Ekspert
27. november 2008 - 18:47 #49
VS 2008 Express:

project properties
build
advanced
check for arithmetic overflow/underflow
Avatar billede arne_v Ekspert
27. november 2008 - 18:52 #51
Avatar billede Slettet bruger
27. november 2008 - 19:23 #52
Tak! Ja, der var sgu overflow (no shit)!
Og ja, F# ser meget lovende ud... Jeg kikker lige på det.
Avatar billede Slettet bruger
27. november 2008 - 19:36 #53
Okaj, jeg er forvirret. Hvad er F#? Et nyt sprog? Hvordan kan jeg bruge det i mit program? Kan jeg eventuelt anvende klasserne som ved de Java-baserede BigInteger og BigDecimal? Jeg er pænt forvirret.
Avatar billede arne_v Ekspert
27. november 2008 - 19:40 #54
F# er et .NET sprog.

Det er sådan OCAML.NET eller en blanding af C# og OCAML.

Ja. Du kan godt bruge F# klasserne fra C#.

BigInt virker perfekt.

BigNum er ikke en BigFloat men en BigRational, hvilket muligvis kan drille lidt.

Her er noget C# kode til at sætte dig igang:

using System;
using System.Text;

using Microsoft.FSharp.Math;

namespace E
{
    public static class MyBigNumExts
    {
        public static BigInt Factorial(int n)
        {
            if(n > 1)
            {
                return BigInt.FromInt32(n) * Factorial(n - 1);
            }
            else
            {
                return BigInt.One;
            }
        }
        public static string MyToString(this BigNum x, int nodec)
        {
            StringBuilder sb = new StringBuilder();
            BigInt n = x.Numerator;
            BigInt d = x.Denominator;
            BigInt intpart =  n / d;
            sb.Append(intpart.ToString());
            n = n - intpart * d;
            sb.Append(".");
            for (int i = 0; i < nodec; i++)
            {
                n = n * BigInt.FromInt32(10);
                intpart = n / d;
                sb.Append(intpart.ToString());
                n = n - intpart * d;
            }
            return sb.ToString();
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine(MyBigNumExts.Factorial(i));
                Console.WriteLine(BigInt.Factorial(BigInt.FromInt32(i)));
            }
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine(BigNum.PowN(BigNum.FromInt(10), i));
            }
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine(BigNum.PowN(BigNum.FromInt(10), i));
            }
            for (int i = 0; i < 50; i++)
            {
                Console.WriteLine(BigNum.PowN(BigNum.FromInt(10), i));
            }
            BigNum onethird = BigNum.One / BigNum.FromInt(3);
            Console.WriteLine(onethird.ToString());
            Console.WriteLine(onethird.MyToString(30));
            Console.ReadKey();
        }
    }
}
Avatar billede Slettet bruger
27. november 2008 - 19:56 #55
Hvad betyder det, at det er rational? At den gemmer værdier som to forskellige, der så divideres ved fortolkning? Og har det nogen praktisk påvirkning af min kode og/eller præcisionen af den endelige applikation?
Avatar billede arne_v Ekspert
27. november 2008 - 20:09 #56
Det giver super præcision. Men du kan ikke bruge ikke-rationelle funktioner som
Log og Sqrt.

Jeg kan ikke vurdere performance impact.
Avatar billede Slettet bruger
27. november 2008 - 20:13 #57
Okay. Men fakultet og opløftning er stadig direkte muligt?
Avatar billede arne_v Ekspert
27. november 2008 - 20:15 #58
Ja.

fac(heltal) er heltal

pow(brøk, heltal) er brøk
Avatar billede Slettet bruger
27. november 2008 - 20:24 #59
Lyder fornuftigt. Jeg tror, jeg vil forsøge at anvende F#'s Math til projektet, så. Men: Hvordan får jeg importeret skidtet i VC#?
Avatar billede arne_v Ekspert
27. november 2008 - 20:34 #60
Du skal bare lave en ref til FSharp.Core.Dll og lave using.
Avatar billede Slettet bruger
27. november 2008 - 21:16 #61
Med alle de tweaks F#-klasserne kræver for at kunne anvendes til projektet, er det vel lige så smart at vælge Java-klasserne? Eller er der noget, jeg overser?
Avatar billede arne_v Ekspert
27. november 2008 - 21:34 #62
Nu ved jeg ikke hvor mange tweaks det er. Du har +-*/ og power og factorial. Jeg
har givet dig den ToString du vil bruge.

Jeg gætter på at det performer bedre end J# klasserne.

Grunden til det er at F# er noget nyt som bliver udvikler og som der er interesse
for. J# var bare noget man skulle have da .NET 1.0 skulle udgives for 6 år siden.
Avatar billede Slettet bruger
27. november 2008 - 22:27 #63
Okay. Så er det nok meget smart at bruge F#... Jeg må lige sætte mig ind i det i morgen formiddag.
Avatar billede arne_v Ekspert
27. november 2008 - 23:02 #64
F# og OCAML er nok en lidt stor mundfuld til en formiddag ...
Avatar billede Slettet bruger
28. november 2008 - 08:39 #65
O'rly?

Ja. Der er nok at lære... Men det er vel også begrænset, hvad jeg behøver at have kendskab til. Jeg prøver lige at strikke noget sammen...
Avatar billede Slettet bruger
28. november 2008 - 08:43 #66
Bør jeg anvende Chew Keongs BigInteger-klasse eller F#'s udgave? Umidelbart kan jeg finde større funktionalitet i Keongs.
Avatar billede Slettet bruger
28. november 2008 - 11:27 #67
Jeg prøver med Keongs først. Der er en masse features, jeg sikkert kan drage nytte af.
Avatar billede Slettet bruger
28. november 2008 - 12:48 #68
Sådan! Nu er koden skrevet med Keongs BigInteger og F#'s BigNum.
Så til debugging!


--- BigNumExtensions ---


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.FSharp.Math;

namespace FChudnovskyTest
{
    public class BigNumExtensions
    {
        public static BigNum Power(BigNum x, BigNum y)
        {
            if (y == BigNum.FromInt(0))
                return BigNum.FromInt(1);
            else if (y == BigNum.FromInt(1))
                return x;
            else
            {
                BigNum z = y / BigNum.FromInt(2);
                return Power(x, z) * Power(x, y - z);
            }
            // This method is needed as the built-in PowN method of the BigNum class does not support decimal numbers as power arguments.
            // I would like to thank Arne Valhøj for contributing to the design of this method as he wrote the initial code.
            // See http://www.eksperten.dk/spm/850647 (Danish) for more information.
        }
    }
}


"An unhandled exception of type 'System.StackOverflowException' occurred in FSharp.Core.dll"

Fejlen trackes til denne linje:

BigNum z = y / BigNum.FromInt(2);

Hvad er der galt?
Avatar billede Slettet bruger
28. november 2008 - 18:07 #69
Slet ingen bud? Jeg skal snart videre med projektet, så alle forslag er kærkomne!
Avatar billede arne_v Ekspert
28. november 2008 - 18:50 #70
power(decimal, decimal) er en lidt tricky funktion - du kan ikke implementere den på
samme måde som power(decimal, integer)
Avatar billede arne_v Ekspert
28. november 2008 - 18:51 #71
Skal du bruge den helt generelt eller kun for 1.5, 2.5, 3.5 etc. ?
Avatar billede Slettet bruger
28. november 2008 - 22:26 #72
3.5 kan gøre det. Hvorfor? Og hvorfor kan jeg ikke bruge den Power-metode?
Avatar billede Slettet bruger
28. november 2008 - 22:27 #73
(Beklager jeg ikke svarede før, men Windows Live Messenger besluttede lige, at jeg ikke skulle informeres om nye postmeddelelser...)
Avatar billede arne_v Ekspert
28. november 2008 - 22:56 #74
Den power metode forudsætter at man rammer præcis 1 eller 0 til sidste. Det er tilfældet med
int - det er ikke tilfældet med float.
Avatar billede arne_v Ekspert
28. november 2008 - 22:57 #75
x^3.5 = x^3*sqrt(x)

sqrt er rimelig nem at implementere.

I rational vil du dog skulle lægge dig fast på en præcision.
Avatar billede Slettet bruger
28. november 2008 - 23:39 #76
Hvad gør jeg så, hvis jeg absolut skal bruge en helt præcis pow-funktion?
Avatar billede arne_v Ekspert
28. november 2008 - 23:48 #77
Det er ikke muligt at lave en helt præcis pow funktion for andet end heltal.

Det er ligesom at skrive PI eksakt !
Avatar billede Slettet bruger
29. november 2008 - 00:40 #78
Okaj. Jeg vil dog sige, at det ikke er helt korrekt at påstå, at pi ikke kan skrives eksakt ;) Teknisk set er
pi = lin[n->uendelig](n*cos(90-180/n))
en eksakt angivelse... Hvis man altså må kalde en grænseværdi eksakt på et teoretisk plan? Bare spekulationer... Og ligningen har desværre ingen praktisk betydning, da den selv ved ekstremt høje n-værdier kun giver ganske få korrekte cifre.

Anyway:
Kan jeg få dig til at give et eksempel på decimal^decimal-metode, der er så præcis som mulig?
Avatar billede arne_v Ekspert
29. november 2008 - 01:09 #79
Skrive er i denne sammenhæng som rationelle tal, fordi din BigNum er rational og
en traditionel floating point også er det (omend lidt mere tricky i format).

Du skal lave enSqrt funktion så kan du bruge 22:57:54.
Avatar billede Slettet bruger
29. november 2008 - 09:07 #80
Og hvordan laver jeg en sqrt?
Avatar billede arne_v Ekspert
29. november 2008 - 16:21 #81
Jeg tror at du kunne spare dig for meget besvær ved at have valgt en C/C++ bigfloat
løsning.

Men anyway:

using System;
using System.Text;

using Microsoft.FSharp.Math;

namespace E
{
    public static class MyBigNumExts
    {
        public static string MyToString(this BigNum x, int nodec)
        {
            StringBuilder sb = new StringBuilder();
            BigInt n = x.Numerator;
            BigInt d = x.Denominator;
            BigInt intpart =  n / d;
            sb.Append(intpart.ToString());
            n = n - intpart * d;
            sb.Append(".");
            for (int i = 0; i < nodec; i++)
            {
                n = n * BigInt.FromInt32(10);
                intpart = n / d;
                sb.Append(intpart.ToString());
                n = n - intpart * d;
            }
            return sb.ToString();
        }
        public static BigNum Sqrt(BigNum x, int nodec)
        {
            BigInt precision = BigInt.Parse("1".PadRight(nodec, '0'));
            BigNum curr = x / BigNum.Parse("10");
            BigNum last;
            BigNum tmp;
            do
            {
                last = curr;
                curr = (last + x / last) / BigNum.Parse("2");
                tmp = curr - last;
                if (tmp.IsNegative) tmp = -tmp;
            }
            while (tmp.Numerator * precision > tmp.Denominator);
            return curr;   
        }
        public static BigNum Pow(BigNum x, BigNum y, int nodec)
        {
            BigInt n = y.Numerator;
            BigInt d = y.Denominator;
            if (n == BigInt.Zero)
            {
                return BigNum.One;   
            }
            else if (n % d == BigInt.Zero)
            {
                if (y.ToString().Length > 9) throw new ArgumentException(y + " is too big an int");
                return BigNum.PowN(x, int.Parse(y.ToString()));
            }
            else if ((BigInt.Parse("2") * n) % d == BigInt.Zero)
            {
   
                return Sqrt(x, nodec) * Pow(x, y - BigNum.Parse("1/2"), nodec);
            }
            else
            {
                throw new ArgumentException(y + " is not int or int + half");
            }
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine(MyBigNumExts.Sqrt(BigNum.Parse("4"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Sqrt(BigNum.Parse("2"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("4"), BigNum.Parse("1/2"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("4"), BigNum.Parse("1"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("4"), BigNum.Parse("3/2"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("4"), BigNum.Parse("2"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("2"), BigNum.Parse("1/2"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("2"), BigNum.Parse("1"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("2"), BigNum.Parse("3/2"), 30).MyToString(30));
            Console.WriteLine(MyBigNumExts.Pow(BigNum.Parse("2"), BigNum.Parse("2"), 30).MyToString(30));
            Console.ReadKey();
        }
    }
}
Avatar billede Slettet bruger
29. november 2008 - 20:35 #82
"Jeg tror at du kunne spare dig for meget besvær ved at have valgt en C/C++ bigfloat
løsning."

Altså skrive det hele i C eller C++ med bigfloat-klassen? Den klasse kender jeg ikke... Og jeg har (desværre) ikke tid til at sætte mig ind i C++ :(

Anyway!

Jeg skal vil kun bruge:

        public static BigNum Sqrt(BigNum x, int nodec)
        {
            BigInt precision = BigInt.Parse("1".PadRight(nodec, '0'));
            BigNum curr = x / BigNum.Parse("10");
            BigNum last;
            BigNum tmp;
            do
            {
                last = curr;
                curr = (last + x / last) / BigNum.Parse("2");
                tmp = curr - last;
                if (tmp.IsNegative) tmp = -tmp;
            }
            while (tmp.Numerator * precision > tmp.Denominator);
            return curr; 
        }
        public static BigNum Pow(BigNum x, BigNum y, int nodec)
        {
            BigInt n = y.Numerator;
            BigInt d = y.Denominator;
            if (n == BigInt.Zero)
            {
                return BigNum.One; 
            }
            else if (n % d == BigInt.Zero)
            {
                if (y.ToString().Length > 9) throw new ArgumentException(y + " is too big an int");
                return BigNum.PowN(x, int.Parse(y.ToString()));
            }
            else if ((BigInt.Parse("2") * n) % d == BigInt.Zero)
            {
 
                return Sqrt(x, nodec) * Pow(x, y - BigNum.Parse("1/2"), nodec);
            }
            else
            {
                throw new ArgumentException(y + " is not int or int + half");
            }
        }

For der er jo allerede en ToString-funktion?
Avatar billede arne_v Ekspert
29. november 2008 - 20:52 #83
Den eksisterende BigNum ToString kan du ikke bruge.
Avatar billede Slettet bruger
30. november 2008 - 00:27 #84
Hvorfor ikke?
Avatar billede arne_v Ekspert
30. november 2008 - 00:35 #85
Fordi den udskriver 0.5 som "1/2" (husk at BigNum er brøker internt).

Og jeg antager du vil have PI med decimaler ikke med en 1000 cifret integer over en
anden 1000 cifret integer.
Avatar billede Slettet bruger
30. november 2008 - 10:07 #86
Awhaw. Ja. Jeg tænkte ikke lige over, at det godt kan blive svært, at omskrive brøken til et decimaltal ;) Jeg kikker lige på det på et tidspunkt i dag. Tak.
Avatar billede Slettet bruger
30. november 2008 - 13:04 #87
Uhm... Kan jeg så ikke højst få 32767 decimaler udskrevet?
Måske skulle jeg forsøge at rode med C++ anyway. Hvilke klasser ville du i så fald anbefale? bigfloat og ... hvad? Og har de klasser alle de nødvendige funktioner indbygget? Hvis det er tilfældet, er det næsten hurtigere for mig at genopfriske C++-konteksten og strikke copy/paste/mod'de min kode til VC++.
Avatar billede arne_v Ekspert
30. november 2008 - 15:04 #88
Hvor skulle MyToString være begrænset til 32767 ?
Avatar billede Slettet bruger
30. november 2008 - 15:11 #89
Fordi dine nodec-parametre vel angiver antal returnerede decimaler?
Avatar billede arne_v Ekspert
30. november 2008 - 15:16 #90
Ja.

int i C# er 32 bit d.v.s. op til 2.1 milliard.
Avatar billede Slettet bruger
30. november 2008 - 15:19 #91
Awhawww!!!
Ja, så er der vist ingen problemer - bortset fra den overflow error jeg får allerede ved en værdi på 1000. Jeg kikker lige på det...
Avatar billede Slettet bruger
30. november 2008 - 20:56 #92
Og så lige for at være besværlig:
Hvilke C++-klasser findes til håndtering af meget store og præcise tal? Måske skulle jeg senere lave et rewrite... Men nu prøver jeg altså det her først uanset hvad.
Avatar billede arne_v Ekspert
30. november 2008 - 21:39 #93
For C/C++ så er GMP nok noget af det bedste.

Det er vist også det man bruger til PI.

http://gmplib.org/pi-with-gmp.html
Avatar billede Slettet bruger
30. november 2008 - 21:54 #94
Jeg er lidt forvirret... Hvad er GMP? Et program, et library, en samlige klasser i kildekode eller et interface? Og hvad er et interface?
Avatar billede arne_v Ekspert
30. november 2008 - 22:59 #95
Et library.
Avatar billede Slettet bruger
30. november 2008 - 23:38 #96
Okaj :) Tak. Jeg kikker på det hele i morgen tidlig.
Avatar billede Slettet bruger
01. december 2008 - 10:16 #97
Det er da til at blive sindssyg af! Nu er halvdelen af min kode pludselig forsvundet... Det ser ud som om, Windows har besluttet sig for at gendanne mine filer, som de var for flere dage siden. Jeg genskriver lige noget, inden jeg vender tilbage her...
Avatar billede Slettet bruger
01. december 2008 - 10:17 #98
Ah, heldigvis havde jeg åbnet en gammel udgave af projektet :) Lige et øjeblik.
Avatar billede Slettet bruger
01. december 2008 - 10:24 #99
Beklager, men det lader til, at der er et problem med din Pow-metode... Prøv at køre følgende kode:


--- Chudnovsky.cs ---

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.FSharp.Math;

namespace FChudnovskyTest
{
    public class Chudnovsky
    {
        public BigInteger Precision = 0;
        public BigNum Result = BigNum.FromInt(0);
        public long Time = 0;

        public Chudnovsky()
        {
        }
        public Chudnovsky(BigInteger n)
        {
            Calculate(n);
        }

        public BigNum Calculate()
        {
            return Calculate(Precision);
        }
        public BigNum Calculate(BigInteger n)
        {
            long time = Environment.TickCount; // Get current ticks
            Precision = n; // Update precision variable
            if (n > 0)
            {
                BigNum result = BigNum.FromInt(0);
                for (BigInteger k = 0; k < n; k++) // Run algorithm
                    result += ( // Let's give the processor a helping hand by first doing all the integer arithmetics
                        new BigInteger(-1).Power(n) *
                            (new BigInteger(6) * n).Faculty() *
                                new BigInteger(13591409) + new BigInteger(545140134) * n /
                                    n.Faculty().Power(new BigInteger(3)) /
                                        (new BigInteger(3) * n).Faculty()
                    ).ToBigNum() / // Now that all the integers are united as a final numerator and converted to a decimal type, let's divide by the denominator
                        BigNumExtensions.Pow(BigNum.FromInt(640320), (new BigInteger(3) * n).ToBigNum() + BigNum.FromInt(3) / BigNum.FromInt(2), 0);
                Result = BigNum.FromInt(1) / BigNum.FromInt(12) / result; // Finally, let's get a clean result
            }
            else
                Result = BigNum.FromInt(0); // Obviously, we won't get a result if we never run the algorithm
            Time = Environment.TickCount - time; // Get ticks spent on conculations
            return Result;
        }
    }
}


--- BigNumExtensions.cs ---

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.FSharp.Math;

namespace FChudnovskyTest
{
    public class BigNumExtensions
    {
        /*
        public static BigNum Power(BigNum x, BigNum y)
        {
            if (y == BigNum.FromInt(0))
                return BigNum.FromInt(1);
            else if (y == BigNum.FromInt(1))
                return x;
            else
            {
                BigNum z = y / BigNum.FromInt(2);
                return Power(x, z) * Power(x, y - z);
            }
            // This method is needed as the built-in PowN method of the BigNum class does not support decimal numbers as power arguments.
        }
        */

        public static string MyToString(BigNum x, int nodec)
        {
            StringBuilder sb = new StringBuilder();
            BigInt n = x.Numerator;
            BigInt d = x.Denominator;
            BigInt intpart = n / d;
            sb.Append(intpart.ToString());
            n = n - intpart * d;
            sb.Append(".");
            for (int i = 0; i < nodec; i++)
            {
                n = n * BigInt.FromInt32(10);
                intpart = n / d;
                sb.Append(intpart.ToString());
                n = n - intpart * d;
            }
            return sb.ToString();
        }
        public static BigNum Sqrt(BigNum x, int nodec)
        {
            BigInt precision = BigInt.Parse("1".PadRight(nodec, '0'));
            BigNum curr = x / BigNum.Parse("10");
            BigNum last;
            BigNum tmp;
            do
            {
                last = curr;
                curr = (last + x / last) / BigNum.Parse("2");
                tmp = curr - last;
                if (tmp.IsNegative) tmp = -tmp;
            }
            while (tmp.Numerator * precision > tmp.Denominator);
            return curr;
        }
        public static BigNum Pow(BigNum x, BigNum y, int nodec)
        {
            BigInt n = y.Numerator;
            BigInt d = y.Denominator;
            if (n == BigInt.Zero)
            {
                return BigNum.One;
            }
            else if (n % d == BigInt.Zero)
            {
                if (y.ToString().Length > 9) throw new ArgumentException(y + " is too big an int");
                return BigNum.PowN(x, int.Parse(y.ToString()));
            }
            else if ((BigInt.Parse("2") * n) % d == BigInt.Zero)
            {

                return Sqrt(x, nodec) * Pow(x, y - BigNum.Parse("1/2"), nodec);
            }
            else
            {
                throw new ArgumentException(y + " is not int or int + half");
            }
        }
        // I would like to thank Arne Valhøj for these methods as he wrote the initial code.
        // See http://www.eksperten.dk/spm/850647 (Danish) for more information.
    }
}


--- Program.cs ---

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.FSharp.Math;

namespace FChudnovskyTest
{
    public class Program
    {
        static void Main(string[] arguments)
        {
            Chudnovsky myChud = new Chudnovsky(1);
            Console.WriteLine(":: Chudnovsky ::\nPrecision: " + myChud.Precision.ToString() + "                (iterations)\nResult:    " + myChud.Result.ToString() + "\nTime:      " + myChud.Time.ToString() + "                (ticks)");
            Console.ReadKey(true);
        }
    }
}


Resultatet er fuldt ud afhængigt af nodec-argumentet og kommer end ikke tæt på pi. Hvad pokker er der galt?
Avatar billede Slettet bruger
01. december 2008 - 10:26 #100
Rettelse:


--- Program.cs ---

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.FSharp.Math;

namespace FChudnovskyTest
{
    public class Program
    {
        static void Main(string[] arguments)
        {
            Chudnovsky myChud = new Chudnovsky(1);
            Console.WriteLine(":: Chudnovsky ::\nPrecision: " + myChud.Precision.ToString() + "                (iterations)\nResult:    " + BigNumExtensions.MyToString(myChud.Result, 20) + "\nTime:      " + myChud.Time.ToString() + "                (ticks)");
            Console.ReadKey(true);
        }
    }
}


Men det går stadig galt -- helt galt :S Tilsyneladende fungerer MyToString heller ikke... Damn it :(
Avatar billede Slettet bruger
01. december 2008 - 20:31 #101
For pokker! Jeg har ingen anelse om, hvordan jeg skal få det til at fungere... Og jeg har knap nok til til at sætte mig ind i detaljerne omkring din kode. Nogen løsningsforslag?
Avatar billede Slettet bruger
01. december 2008 - 20:45 #102
Hm, hvad med http://mathnet.opensourcedotnet.info/ ? Kan det måske bruges? Jeg kan ikke rigtig gennemskue det... Der er godt nok mange funktioner i projektet.
Avatar billede arne_v Ekspert
02. december 2008 - 02:16 #103
Jeg kan ikke se at iridium skulle have bigint/bigfloat.
Avatar billede arne_v Ekspert
02. december 2008 - 02:24 #104
Jeg kan ikke umiddelbart compile din kode, da jeg ikke har BigInteger.

Så du bliver ligesom nødt til at beskrive hvad "det går stadig galt -- helt galt"
dækker over.

Generelt ville jeg nok bruge F# BigInt når du bruger F# BigNum for at simplificere
tingene.
Avatar billede Slettet bruger
02. december 2008 - 10:30 #105
http://www.codeproject.com/KB/cs/biginteger.aspx?target=biginteger

nodec=0
precision=1
pi=-1156270997952937.-5-5-5-6-1-5-2-4-30-5-5-10-7-1-3-3-6-3
time=250

nodec=10
precision=1
pi=-1156270997935222.-1-6-8-1-7-6-6-5-2-50-7-9-20-5-1-5-2-2
time=3105

nodec=10
precision=5
result=-2954444239555281096706279726974429176158350204949902744.-2-2-8-3-4-5-4-2-9-7-3-7-7-80-6-8-3-8-3
time=16692
Avatar billede Slettet bruger
02. december 2008 - 15:05 #106
Fuck, hvor er det frustrerende. Jeg ville ønske, der fandtes en samling matematikklasser til C#, hvor der ikke manglede alverdens elementære metoder (pow/roots, to-decimal-string, ...) :(
Avatar billede Slettet bruger
04. december 2008 - 15:34 #107
Projektet slutter i morgen... Så bare lad det ligge. Jeg må klare mig med 14 decimaler (øv!).
Avatar billede arne_v Ekspert
08. december 2008 - 02:58 #108
Jo. Men C# er tilsyneladende efter både Java og C/C++ på dette område.

Jeg hentede BigInteger klassen fra det link (det var mig der gav linket 50 indlæg
oppe). Men koden compilede stadig ikke (mangler Power).
Avatar billede Slettet bruger
23. februar 2009 - 11:00 #109
Sådan. Jeg fik for nyligt projektet tilbage, og da jeg ledte efter et gammelt spørgsmål på Eksperten, stødte jeg på denne tråd. Tilsyneladende kommer man langt med at bortforklare og snakke udenom, for jeg fik topkarakter for arbejdet :)
Tak for hjælpen - og ved indlæg 109 tror jeg godt, vi kan kalde emnet gennemarbejdet.
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