Hur kan jag räkna ut stora tal såsom 10^100 i vb utan att få Overflow? dim a as double Det "enklaste" är troligtvis att göra egna funktioner som använder sig av strängar. <code> Ja, det är ju precis samma metod, fast med strängar istället. Ah ok, ja det kan nog tänkas att det skulle bli enklare att hantera det. Man slipper ju array-hanteringen... Jag kan ge ett kort exempel på hur man skulle kunna göra exempelvis en additionsrutin: Eller så använder man en rekursiv funktion. Jag älskar rekursiva funktioner, ni som vart med sen Men koden är ju såpass basic att jag nog tycker att det är tillräckligt enkelt för att inte skriva om det till en rekursiv grej. Personligen tycker jag inte att en rekursiv variant är snyggare i detta fallet, och ärligt talat tror jag att min är lättare att förstå. Visst är det en viss tröskel att kliva över innan man fattar konceptet rekursiva funktioner. Tjo igen, <b>>Men håll med om att i sina sammanhang är dom kraftfulla och snygga. Det är som poesi Vissa problem kan inte lösas utan rekursion (om man inte använder en stack för att simulera rekursion).Stora tal i visual basic
Sv: Stora tal i visual basic
a=10^100
A double-precision floating-point value with a range of – 1.79769313486232E308 to – 4.94065645841247E-324 for negative values, 4.94065645841247E-324 to 1.79769313486232E308 for positive values, and 0.
[Peter.H]Sv: Stora tal i visual basic
Rimligare är att leta efter något bibliotek som kan lösa det åt dig.Sv: Stora tal i visual basic
MsgBox "1" & String(100, "0")
</code>
Nä, skämt åsido. Jag har en klass som kan räkna (well, plus och minus, samt potenser, men ej multplikation och division) men den är skriven i C#.
Jag gjorde helt enkelt en klass som innehöll en array av Long. Sedan utför jag beräkningarna precis som när man räknar på papper, men med ett long i taget. Varje long innehåller ett antal positioner av det stora talet, lämpligen hälften av vad datatypen klarar av (för att multiplikationer skall klaras av utan overflow)
Trivialt exempel där vi räknar med att varje long innehåller två siffror dvs mellan 0 och 99. Talet 1234 blir då alltså en array med två long som båda innehåller talet 22. Multiplicerar vi detta med 39 så får vi (om vi börjar från höger):
<info>
34
* 39
----
1326
</info>
Produkten 1234*39 slutar alltså med siffrorna 26. 13 måste vi föra över som rest till nästa multiplikation :
<info>
12
* 39
----
468
+ 13 (rest från förra multiplikationen)
----
481
</info>
Eftersom 481 är större än 100 får vi dela även detta i två delar så resultatet blir en array med tre long : 4, 84 och 26. 1234*39 är alltså 48126.
Det blir givetvis lite mer komplicerat när båda talen är större än 99, men det kan du nog lista ut. Addition och subtraktion är betydligt enklare.
Eftersom du använder VB6 så är 32-bitars long den bästa datatypen, och den klarar 9 siffror totalt (ja 10 siffror men bara upp till drygt 2 miljarder), så eftersom du måste kunna utföra multiplikationer utan overflow så får du använda 4 positioner, dvs tal mellan 0 och 9999 i varje position. För ett hundrasiffrigt tal behöver du alltså en array på 25 longs.
Så skulle jag löst det...nyfiken dock på Niklas förslag med strängar?Sv:Stora tal i visual basic
Det blir troligtvis aningen segare med strängar men å andra sidan tycker jag att de är enklare att hantera.Sv: Stora tal i visual basic
Sv: Stora tal i visual basic
Man förväntar sig att a och b båda är talen skrivna baklänges.
Public Function StringAdd (a As String, b As String) As String
Dim Pos As Long, MaxPos As Long, Result As String, Sum as long, minne as long
MaxPos=Max(Len(a), Len(b))
Result =String$(MaxPos, "0")
minne=0
For Pos= 1 to maxpos
Sum=Asc(Mid$(a, pos, 1))+Asc(Mid$(b, pos,1))+minne
Minne=sum \ 10
Mid$(Result, pos, 1)=sum mod 10
Next Pos
Result=Result & minne
StringAdd = Result
End Function
Något i den stilen. Sen måste man ha kontroller för när ena strängen tar slut, se till att strängarna inte har massa nollor, osv. Sv:Stora tal i visual basic
längre tillbaka känner till detta. Jag presenterar här min rekursiva strAddRek funktion som klarar
att addera två tal i strängform. Den har dock brister. Denna version klarar endast positiva tal.
Med rekursiva funktioner får man ofta enkla, snygga samt lättbegripliga lösningar.
Det kan vara krångligt för nybörjaren att förstå hur det fungerar. Men i princip kan man säga att
det handlar om "Divide et impera" (Söndra och härska). Man bryter ner problemet i småproblem.
I detta fall, vad innebär det att addera två jättelånga tal. Jo att addera ett och ett tal tills hela talet
är adderat. Precis så gör den rekursiva funktionen. Adderar tal för tal tills det blir färdigt. Jamen
säger du, det gör ju loopen med. Japp alldeles riktigt. Men en loop-koden är inte lika lätt att sätta
sig in i och förstå principen av.
Koden går naturligtvis att krympa ner, men då blir den otydlig och krånglig att förstå... jag har valt att använda så här många lokala variabler och så för att göra det mer tydligt. jmfr. med loop-kodens rad:
<code>
Sum=Asc(Mid$(a, pos, 1))+Asc(Mid$(b, pos,1))+minne
</code>
Kanske inte exakt solklart vad som händer ;) ;)
Nåja. Jag kommer nog få massa respons nu på detta inlägg :D det är skoj. Men nu ska jag visa koden
för den rekursiva varianten.
<code>
Option Explicit
Private Function strAddRek(parts As Variant) As String
Dim term1 As Integer
Dim term2 As Integer
Dim delsumma As String
Dim tmp As String
Dim minne As String
If parts(0) <> "" Or parts(1) <> "" Or parts(2) <> "" Then 'Stoppvilkor
parts(0) = IIf(parts(0) = "", "0", parts(0)) '0-utfyllnad vid behov
parts(1) = IIf(parts(1) = "", "0", parts(1)) '0-utfyllnad vid behov
term1 = CInt(Right(parts(0), 1)) '1:a termen
term2 = CInt(Right(parts(1), 1)) '2:a termen
minne = Val(parts(2)) 'Minne från föregående addition
tmp = Format(term1 + term2 + minne, "0") 'Summera
delsumma = Right(tmp, 1) 'Ta ut delsumma ental
parts(3) = delsumma & parts(3) 'Lägg till delsumman till totalsumman
parts(0) = Left(parts(0), Len(parts(0)) - 1) 'Återstoden av term1 som ska beräknas
parts(1) = Left(parts(1), Len(parts(1)) - 1) 'Återstoden av term2 som ska beräknas
parts(2) = Left(tmp, Len(tmp) - 1) 'Minne till nästa addition.
strAddRek = strAddRek(parts) 'Anropa nästa addition rekursivt
Else
strAddRek = parts(3) 'Stoppvilkor uppfyllt, returnera svar
End If
End Function
Private Sub Command1_Click()
Dim a As Variant
ReDim a(3)
a(0) = "98273540970598732098734508972340897346897457609235876345"
a(1) = "98345698230983254689054089756763456234564569836089746897246"
a(2) = "0"
a(3) = ""
MsgBox strAddRek(a)
End Sub
</code>
[Peter.H]Sv: Stora tal i visual basic
Sv:Stora tal i visual basic
Ofta löser man problemen lika enkelt med loopar som med rekursiva funktioner. Ibland
är en rekursiv lösning rent utav sämre. Det är en smaksak. Jag använder gärna rekursiva
funktioner om jag kan och det medger en snyggare lösning.
I detta fallet är det som du säger kanske varken snyggare eller enklare kanske...
Men håll med om att i sina sammanhang är dom kraftfulla och snygga. Det är som poesi
eller konst ;)
[Peter.H]Sv: Stora tal i visual basic
Jag tycker nog niklas lösning var den enklaste men tack för hjälpen alla :)Sv: Stora tal i visual basic
eller konst ;)</b>
Jo, är ett problem definierat på ett rekursivt sätt är de rekursiva lösningarna i allmänhet snygga. Sen ska man tänka på att i tidskritiska grejer så kräver rekrusion en del overhead i både minne och fart.Sv:Stora tal i visual basic
Vid s k svansrekursion kan koden skrivas om till en loop (av kompilatorn). Sådan är dock inte alltid tillämpbar.