|
-
Nov 22nd, 2011, 04:14 PM
#41
Thread Starter
Hyperactive Member
Re: Creating User-Defined Types.
 Originally Posted by dbasnett
It is daves thread, but moving it to the math forum might prove enlightening. There are some incredibly bright people there.
up to you guys, as long as you all fallow it there. I'm liking this help you've all provided here. I just hope the guys in the math forum aren't too bright to where I struggle to fallow.. seeing as I'm struggling enough as it is here
-
Nov 22nd, 2011, 04:21 PM
#42
Re: Creating User-Defined Types.
Are we all agreed, math forum? I'll get it moved if we are.
-
Nov 22nd, 2011, 04:50 PM
#43
Re: Creating User-Defined Types.
 Originally Posted by dbasnett
Are we all agreed, math forum? I'll get it moved if we are.
I'm unsure about moving it. This thread has thrown up a some interesting things about structures, precision and number formats. They may be dotnet/computing matters rather VB.Net (apart from the examples). But wouldn't these aspects have been missed on the Math forum? BB
-
Nov 22nd, 2011, 05:27 PM
#44
Re: Creating User-Defined Types.
-
Nov 22nd, 2011, 07:20 PM
#45
Re: Creating User-Defined Types.
I saw this linked from the math forum. My own thoughts:
This project has been done before a number of times. A brief search found http://sine.codeplex.com/ (amongst others just for .NET). Still, this type of project can be very educational and can also be fun. Certainly, if you're enjoying it, don't stop just because it's been done before. Just keep in mind when it is and isn't worth the time to reinvent the wheel.
Ok, the responsible side of me has been satisfied well enough. Two formats have been proposed, and I have some of my own. I'll list them with pros and cons.
- A BigInt holding the integer part, and a BigInt holding the fractional part.
- Pros: Mirrors how a human typically thinks about decimals.
- Cons: You might be tempted to implement your own addition routine to deal with fractional addition (though this can be avoided by multiplying one of the addends by a suitable power of 10). Multiplication is a 4-part operation involving some tedious reasoning. I'm not immediately sure how division could be done.
- A single BigInt holding the mantissa, and another BigInt (well, I would use a BigInt) holding the exponent.
- Pros: You don't have to split every calculation into pieces like with the above method. Multiplication is extremely easy. Addition does not have to be difficult either, as above.
- Cons: Actually, I don't really see any. This is very similar to the format the IEEE settled on for floating point numbers, just with an arbitrary-length mantissa. It makes sense that it's a very good option. Come to think of it, division would be somewhat difficult.
- Note: You might want to look in to a base 2 exponent rather than base 10. Multiplication by 2 is likely very fast on BigInts (and if it's not, it should be). If you do this, though, you'll have to convert to base 10 to display results.
- Arbitrary-precision rational numbers, using a BigInt for the numerator and another BigInt for the denominator.
- Pros: Allows you to store rational numbers without loss of precision. Fundamentally, pretty much everything is built up from basic operations on rational numbers. Also, the Euclidean Algorithm is fast enough to allow you to cancel like terms from the numerator and denominator, keeping things small-ish and allowing you to implement equality testing trivially. Addition, subtraction, multiplication, and division are all simple extensions of the relevant BigInt operations, followed by canceling like terms.
- Cons: The rational numbers involved can get huge. For practicality's sake you would probably have to implement a "round" routine which trimmed the denominator down to some specified size. That routine would be somewhat interesting to come up with. Also, the ToString() method would need a fair amount of work.
- This one is a bit advanced. Allow arbitrary-precision rationals, together with a set of definable symbols (eg. pi, e). An object would be some (finite) combination of rationals, symbols, and operations (+, -, /, *, etc.).
- Pros: I imagine this is essentially what computer algebra systems use. It would be a wonderful exercise in recursively defined data types.
- Cons: Of very questionable use without a computer algebra system behind the data type to perform simplifications automatically.
There were a few other ideas I wanted to mention.
First is an "exact" flag. A BigDecimal would start with exact = True. Whenever a BigDecimal is created through addition, multiplication, etc., if any rounding occurs whatsoever, exact gets set to False. exact = False propagates as well--adding an exact to an inexact value creates an inexact value. This would probably be most useful with rational numbers.
Second, you may wish to allow the user to specify the precision of intermediate results in addition to the precision of a BigDecimal. Some operations may require several steps (eg. taking integer powers), and you should use more precision in those intermediate steps than actually required to prevent rounding errors from accumulating in the last few places.
Third, if your numbers... actually, I forgot number three. Oh well. Edit: I remembered my point. Be careful about combining precision on different numbers. For instance, adding 37 and 1.0004 increases the precision in 37 to 4 digits after the decimal. Multiplication and division can be trickier.
Last edited by jemidiah; Nov 22nd, 2011 at 07:41 PM.
The time you enjoy wasting is not wasted time.
Bertrand Russell
<- Remember to rate posts you find helpful.
-
Nov 22nd, 2011, 07:30 PM
#46
Re: Creating User-Defined Types.
I think that this thread shouldn't be moved. The Math forum is a great place for hard-core feats of engineering, but this isn't just about a single calculation. Its about creating a programming data type for use IN calculations. I think that that alone makes it worth keeping in this section as it will pertain mostly to programming.
Before we start to turn this whole thread into a debate on where to move it, I still think #2 is the best way to go. Its simple in concept, and has the fewest drawbacks. I also agree that using a Bigint for the Exponent, however I think there should be a defined limit to how many decimals it can go out to. (on a per variable basis)
What I mean by that is, going back to the infinite loop example, we don't want to create something soo huge that it uses up your entire computer's ram. But we do want someone who has 256GB of ram on their custom server board to have the option to calculate PI to enough digits to be reading it for 100 lifetimes.
-
Nov 23rd, 2011, 01:05 AM
#47
Thread Starter
Hyperactive Member
Re: Creating User-Defined Types.
This is what I've come together for a BigDouble... No operations yet, but simply can store the value. Having that I'm only using a single BigInteger will make the operations and calculations easy and quick. So it wont be to long before I have that added and posted. Tomorrow is my estimation of an update.
vbnet Code:
Public Structure BigDouble
Private _Value As BigInteger
Public Property Value As BigInteger
Get
Return Me._Value
End Get
Set(ByVal value As BigInteger)
Me._Value = value
End Set
End Property
Private LeadingZeros As Int32
Private _DecimalPosition As Int32
Public Property DecimalPosition As Int32
Get
Return Me._DecimalPosition
End Get
Set(ByVal value As Int32)
Me._DecimalPosition = value
End Set
End Property
Public Shared Function Zero() As BigDouble
Dim output As New BigDouble
With output
.Value = 0
.DecimalPosition = 0
.LeadingZeros = 0
End With
Return output
End Function
Public Function TryParse(ByVal value As String) As BigDouble
Dim output As BigDouble = BigDouble.Zero
Try
Dim tmp As String = value.Replace(".", vbNullString)
'There can only be one decimal point within a value.
If value.IndexOf("."C) = value.LastIndexOf("."C) Or Not value.Contains(".") Then
With output
BigInteger.TryParse(tmp, .Value)
.DecimalPosition = value.IndexOf("."C)
'Locate and count each leading zeros.
For i As Int32 = 0 To tmp.Length-1
If tmp.Substring(i,1) = "0" Then
.LeadingZeros += 1
Else: Exit For 'Exit out at the first non zero found(all zeros if any have been located and accounted for).
End If
Next
End With
Else
Throw New ParseException
End If
Catch ex As ParseException
MessageBox.Show(ex.Message)
End Try
Return output
End Function
Public Overrides Function ToString() As String
Dim tmp As String = Value.ToString
If Value > 0 Then 'Check if the value is greater than 0.
tmp = tmp.PadLeft(tmp.Length+LeadingZeros, "0"C)
If DecimalPosition >= 0 Then
tmp = tmp.Insert(DecimalPosition, ".")
If tmp.IndexOf("."C) = 0 Then tmp = "0" & tmp
End If
End If
Return tmp
End Function
Public Class ParseException
Inherits System.Exception
Public Shadows ReadOnly Property Message As String
Get
Return "Parse has failed to convert the provided string into a BigDouble!"
End Get
End Property
End Class
End Structure
-
Nov 23rd, 2011, 01:10 AM
#48
Thread Starter
Hyperactive Member
Re: Creating User-Defined Types.
 Originally Posted by jemidiah
[LIST=1][*]A BigInt holding the integer part, and a BigInt holding the fractional part.
- Pros: Mirrors how a human typically thinks about decimals.
- Cons: You might be tempted to implement your own addition routine to deal with fractional addition (though this can be avoided by multiplying one of the addends by a suitable power of 10). Multiplication is a 4-part operation involving some tedious reasoning. I'm not immediately sure how division could be done.
This was actually my first attempt and wast working properly.. though I scratch it yet haven't gotten rid of it yet. But by doing so I noticed doing something such as simple additions was a lot of work. So I couldn't even imagine the amount of work required to do divison and such.
The example I just posted simply uses a single BigInteger and I keep track of the decimal place and any leading zeros(again cause converting 0.000001 to a BigInteger value will give you 1, so I keep track of those leading zeros and place them back in the ToString function.
-
Nov 23rd, 2011, 04:08 AM
#49
Re: Creating User-Defined Types.
Perhaps I should have championed rational numbers, option #3, more in my previous post. That seems like an option worth pursuing, far more so than option #1. Of course, option #2 is also good, which seems to be what you've chosen.
The purpose of having both "LeadingZeros" and "DecimalPosition" is not clear to me. You should be able to use a single number to holding the exponent, as in scientific notation, and infer the decimal place from that. I would actually use "Exponent" rather than "DecimalPosition".
Ex: 0.000001 -> Value = 1, Exponent = -6, since 0.000001 = 1 * 10^(-6).
The time you enjoy wasting is not wasted time.
Bertrand Russell
<- Remember to rate posts you find helpful.
-
Nov 23rd, 2011, 07:39 AM
#50
Re: Creating User-Defined Types.
 Originally Posted by jemidiah
[*]Arbitrary-precision rational numbers, using a BigInt for the numerator and another BigInt for the denominator.
- Pros: Allows you to store rational numbers without loss of precision. Fundamentally, pretty much everything is built up from basic operations on rational numbers. Also, the Euclidean Algorithm is fast enough to allow you to cancel like terms from the numerator and denominator, keeping things small-ish and allowing you to implement equality testing trivially. Addition, subtraction, multiplication, and division are all simple extensions of the relevant BigInt operations, followed by canceling like terms.
- Cons: The rational numbers involved can get huge. For practicality's sake you would probably have to implement a "round" routine which trimmed the denominator down to some specified size. That routine would be somewhat interesting to come up with. Also, the ToString() method would need a fair amount of work.
I made a fractions class with big integers, and the ToString isn't all that complicated
vb.net Code:
Public Overloads Function ToString(ByVal Digits As Integer) As String Dim st As New System.Text.StringBuilder(Digits + 1) Dim result As BigInteger = _Numerator / _Denominator Dim left As BigInteger = _Numerator Mod _Denominator st.Append(result) If left <> 0 Then st.Append("."c) For i = 1 To Digits If left < _Denominator Then left *= 10 result = left / _Denominator If result = 0 Then Exit For left = left Mod _Denominator st.Append(result) Next Return st.ToString End Function
The variable names are self explanatory.Only thing it doesn't do is round the last digit. I will post it in the codebank when it is done.
Last edited by BlindSniper; Nov 23rd, 2011 at 07:54 AM.
-
Nov 23rd, 2011, 11:26 AM
#51
Thread Starter
Hyperactive Member
Re: Creating User-Defined Types.
I see the Exponent and my LeadingZeros almost working in the same way just expanded. To have the exponent say (-6) if my value is 1 then I still have to determine if I require any leading zeros or not. Which in this case I do so I would have to figure that out, and the exponent variable would be my key to exactly how many. Where as my LeadingZeros variable has already been determined when I parsed the value and directly tells me how many I need when rather figuring it out each time I return the value as a string.
I can try it real quick and see how well I can adapt to using an exponent rather leading zeros and perhaps the benefits of doing such. I only have like half an hour before my next class but I'll get to coding and have something for you guys in a few.
EDIT: I really enjoy this post to by the way. It's getting me to think outside of the box, and expand my thinking and knowledge of other options I have available that I hadn't known prior.
Last edited by DavesChillaxin; Nov 23rd, 2011 at 11:44 AM.
-
Nov 23rd, 2011, 12:57 PM
#52
Thread Starter
Hyperactive Member
Re: Creating User-Defined Types.
I'm not sure why I'm not getting this here, but as you say 1x10^-6 = 0.000001 right?
so what does 100x10^-6 = ?.. I'm not sure but I'm getting a headache here cause I'm really not getting it right now for some reason.
-
Nov 23rd, 2011, 01:36 PM
#53
Re: Creating User-Defined Types.
 Originally Posted by DavesChillaxin
1x10^-6 = 0.000001 right?
Yes.
 Originally Posted by DavesChillaxin
100x10^-6 = ...
0.0001
The time you enjoy wasting is not wasted time.
Bertrand Russell
<- Remember to rate posts you find helpful.
-
Nov 23rd, 2011, 03:52 PM
#54
Re: Creating User-Defined Types.
 Originally Posted by DavesChillaxin
I'm not sure why I'm not getting this here, but as you say 1x10^-6 = 0.000001 right?
so what does 100x10^-6 = ?.. I'm not sure but I'm getting a headache here cause I'm really not getting it right now for some reason.
As a quick rule of thumb:
A x 10 ^ B = Move the Decimal in A to the --> B spaces
and
A x 10 ^ -B = Move the Decimal in A to the <-- B spaces
I know its simple, but its easy to have something to look at, rather than have to remember the simple things
-
Nov 23rd, 2011, 09:29 PM
#55
Thread Starter
Hyperactive Member
Re: Creating User-Defined Types.
 Originally Posted by jemidiah
Okay okay, thats actually what I had produced with the code I put together earlier. Just I'm not sure why but it just wasn't clicking with me. I thought it was all wrong and got frustrated though what I thought was just as stepdragon had said. Negatives move the the left where as positives move to the right. Back to work!
Last edited by DavesChillaxin; Nov 23rd, 2011 at 09:59 PM.
-
Nov 24th, 2011, 05:27 PM
#56
Thread Starter
Hyperactive Member
Re: Creating User-Defined Types.
First I'd like to say Happy Thanksgiving to you all! I hope your day was a great as mine.
Also I've had a lot more success with this project. I noticed a few speed bumps along the way and may need a little clarification.
Here's a few examples of what I can produce so far. You also may notice a few things as I did.
- Parse: 1.00000489373748
Output 1.00000489373748(Decimal Notation), 100000489373748ᴇ-14(Scientific Notation) - Parse: 1.009
Output 1.009(Decimal Notation), 1009ᴇ-3(Scientific Notation) - Parse: 0.00000000000000013938
Output 0.00000000000000013938(Decimal Notation), 13938ᴇ-20(Scientific Notation) - Parse: 0
Output 0.0(Decimal Notation), 0ᴇ-1(Scientific Notation) - Parse: 100
Output 0.100(Decimal Notation), 100ᴇ-3(Scientific Notation) - Parse: 0.00000000000001
Output 0.00000000000001(Decimal Notation), 1ᴇ-14(Scientific Notation)
Now what I first had noticed was the fact I could get away without using any positive exponents. For the purpose of just storing the data I could use only negative exponents. So far it's been working as you can see, just I'm unaware of it having any flaws yet
Secondly I studied up on scientific notations I stumbled across "normalized notation" Which is the a, or coefficient of a scientific notation should be less than 10.. This was my first road bump. I tried fallowing this rule but shortly after my first attempt I realized I store my coefficient as a BigInteger. Which is my key to limitless precision. To fix that I'd have to use the type inside itself or use my other BigDecimal type.. I felt this was pointless seeing that 3*10^3, 30*10^2, and 300*10^1 are all equal. Besides in the end the user wont have access to any of this and is simply just for the sake of storing data in a way I can format it later in Decimal Notation. So I concluded I wouldn't have to fallow all the rules, just so long as my output(in decimal notation) was always correct to what the user parsed.
I also know the 100, should trim the trailing 0's. I'm getting to that shortly..
But other than that let me know what you think and if you agree.
-
Nov 24th, 2011, 07:03 PM
#57
Re: Creating User-Defined Types.
 Originally Posted by DavesChillaxin
First I'd like to say Happy Thanksgiving to you all! I hope your day was a great as mine.
Also I've had a lot more success with this project. I noticed a few speed bumps along the way and may need a little clarification.
Here's a few examples of what I can produce so far. You also may notice a few things as I did.
- Parse: 1.00000489373748
Output 1.00000489373748(Decimal Notation), 100000489373748ᴇ-14(Scientific Notation) - Parse: 1.009
Output 1.009(Decimal Notation), 1009ᴇ-3(Scientific Notation) - Parse: 0.00000000000000013938
Output 0.00000000000000013938(Decimal Notation), 13938ᴇ-20(Scientific Notation) - Parse: 0
Output 0.0(Decimal Notation), 0ᴇ-1(Scientific Notation) - Parse: 100
Output 0.100(Decimal Notation), 100ᴇ-3(Scientific Notation) - Parse: 0.00000000000001
Output 0.00000000000001(Decimal Notation), 1ᴇ-14(Scientific Notation)
Now what I first had noticed was the fact I could get away without using any positive exponents. For the purpose of just storing the data I could use only negative exponents. So far it's been working as you can see, just I'm unaware of it having any flaws yet
Secondly I studied up on scientific notations I stumbled across "normalized notation" Which is the a, or coefficient of a scientific notation should be less than 10.. This was my first road bump. I tried fallowing this rule but shortly after my first attempt I realized I store my coefficient as a BigInteger. Which is my key to limitless precision. To fix that I'd have to use the type inside itself or use my other BigDecimal type.. I felt this was pointless seeing that 3*10^3, 30*10^2, and 300*10^1 are all equal. Besides in the end the user wont have access to any of this and is simply just for the sake of storing data in a way I can format it later in Decimal Notation. So I concluded I wouldn't have to fallow all the rules, just so long as my output(in decimal notation) was always correct to what the user parsed.
I also know the 100, should trim the trailing 0's. I'm getting to that shortly..
But other than that let me know what you think and if you agree.
Is that an error or a typo? I saw you explained the trailing zeros, but what about the fact that you input 100 and output .1
also, happy thanksgiving back to you
-
Nov 25th, 2011, 01:07 AM
#58
Re: Creating User-Defined Types.
I wouldn't call your format (#2 in my list) "scientific notation". Don't let the "mantissa < 10" convention in real scientific notation bother you. It's best to just ignore it here, as you seem to have concluded.
I also wouldn't ignore positive exponents. Consider the number 1234 * 10^(10^(10 trillion)). The exponent has approximately 10 trillion digits, even though your number only has 4 digits of precision. If you disallow positive exponents, you would need to store all 10 trillion digits, even though all but 4 are 0.
The time you enjoy wasting is not wasted time.
Bertrand Russell
<- Remember to rate posts you find helpful.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|