Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

Authors

Search

XML Feeds

Google Ads

« SQL Server Application and Multi-Server Management Private CTPSecuring your password for SQL Server 2005 and 2008 and more »
comments
Rate Post:
submit to reddit Digg!FacebookDotnetkicks

This probably falls under the category of 'Why bother'. However, there has been some recent interest in calculating arbitrarily large fibonacci numbers. There is nothing particularly difficult about calculating these numbers until you reach the maximum number that a bigint (or decimal) can hold. With Fibonacci numbers, you reach this limit pretty fast. There's nothing particularly difficult about calculating this sequence, it merely involves adding 2 numbers together. But, since we run in to the data type limit, we need to start thinking outside the box.

Obviously, we cannot store the numbers in any sort of number data type, so we need to use strings instead. Then, we need to create a way to add strings together as though they were numbers. This is the real challenge with calculating large numbers, but it's really not that difficult either. We'll simply write a function that adds 2 strings together as though they were numbers.

Please understand that this is not production quality code. I'm not validating the inputs and I'm being careless about the data type conversions. Also note that I use the varchar(max) data type. This implies SQL2005 code. If you want to test this on SQL2000, then you'll need to replace varchar(max) with VarChar(8000). You won't be able to calculate as many numbers, but you'll still get quite a few.

  1. CREATE FUNCTION dbo.AddString(@String1 VARCHAR(8000), @String2 VARCHAR(8000))
  2. RETURNS VARCHAR(MAX)
  3. AS
  4. BEGIN
  5.     DECLARE @CarryTheOne INT
  6.     DECLARE @i INT
  7.     DECLARE @OUTPUT VARCHAR(MAX)
  8.     DECLARE @Digit1 INT
  9.     DECLARE @Digit2 INT
  10.  
  11.     IF LEN(@String1) < LEN(@String2)
  12.         SELECT @String1 = REPLACE(RIGHT(SPACE(LEN(@String2)) + @String1, LEN(@String2)), ' ', '0')
  13.     ELSE
  14.         SELECT @String2 = REPLACE(RIGHT(SPACE(LEN(@String1)) + @String2, LEN(@String1)), ' ', '0')
  15.  
  16.     SET @CarryTheOne = 0
  17.     SET @i = 0
  18.     SET @OUTPUT = ''
  19.  
  20.     WHILE @i < LEN(@String1)
  21.         BEGIN
  22.             SET @Digit1 = SUBSTRING(@String1, LEN(@String1) - @i, 1)
  23.             SET @Digit2 = SUBSTRING(@String2, LEN(@String1) - @i, 1)
  24.            
  25.             SELECT @OUTPUT = CONVERT(VARCHAR(MAX), (@Digit1 + @Digit2 + @CarryTheOne) % 10) + @OUTPUT
  26.             IF @Digit1 + @Digit2 + @CarryTheOne > 9
  27.                 SET @CarryTheOne = 1
  28.             ELSE
  29.                 SET @CarryTheOne = 0
  30.        
  31.             SET @i = @i + 1
  32.    
  33.         END
  34.    
  35.     IF @CarryTheOne = 1
  36.         SET @OUTPUT = '1' + @OUTPUT
  37.    
  38.     RETURN @OUTPUT
  39. END

The user defined function shown above allows us to add strings as though they were numbers. Now, how do we calculate the fibonacci series? Like this:

  1. DECLARE @Temp TABLE(Id INT IDENTITY(1,1), FIB VARCHAR(MAX))
  2.  
  3. INSERT INTO @Temp(FIB) VALUES('0')
  4. INSERT INTO @Temp(FIB) VALUES('1')
  5.  
  6. DECLARE @i INT
  7. SELECT @i = MAX(Id) FROM @Temp
  8.  
  9. WHILE @i < 1000
  10.     BEGIN
  11.    
  12.         INSERT INTO @Temp(FIB)
  13.         SELECT dbo.AddString((SELECT Fib FROM @Temp WHERE Id = @i), (SELECT Fib FROM @Temp WHERE Id = @i-1))
  14.  
  15.         SET @i = @i + 1
  16.  
  17.     END
  18.  
  19. SELECT Fib FROM @Temp ORDER BY Id

That's all there is to it!

About the Author

George has been developing software professionally for 19 years, first for the department of defense, and then for various other companies. In 1998, George started his software company, Orbit Software, specializing in School Bus Transportation software. His specialty is refining SQL Server queries to deliver optimal performance.
Social SitingsTwitterLTD RSS Feed
1459 views
submit to reddit Digg!FacebookDotnetkicks

Comments and Feedback

4 comments

Comment from: chrissie1 [Member] Email
Perhaps it would e intersting to hear how high people can make it go on their machine. in a reasonable amount of time.
02/12/08 @ 14:53
Comment from: Mike Hadlow [Visitor] · http://mikehadlow.blogspot.com
*****
Nice article, I did the same with 'when' and recursion:

http://mikehadlow.blogspot.com/2007/11/t-sql-fibonacci-and-power-of.html
03/12/08 @ 08:25
Comment from: George Mastros [Member] Email
Mike,

Thanks for the comment, but I think you missed the point of my blog. Your code limits you to the max number an int allows. It's easily converted to bigint, but you are still limited to calculating the first 88 fibonacci numbers. This code, because it uses string arithmetic, has no such limit.
03/12/08 @ 08:40
Comment from: Emtucifor [Member] Email
*****
I made my own addstring function just because I could and it was fun:

CREATE FUNCTION dbo.AddStringErik(@String1 VARCHAR(8000), @String2 VARCHAR(8000))
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE
@i int,
@v int,
@OUTPUT VARCHAR(MAX)
SET @v = 0
SET @OUTPUT = ''
SELECT @i = (Max(a) + 8) / 9 * 9 FROM (SELECT Len(@String1) UNION ALL SELECT Len(@String2)) X (a)
SET @String1 = REPLICATE('0', @i - Len(@String1)) + @String1
SET @String2 = REPLICATE('0', @i - Len(@String2)) + @String2
SET @i = @i - 8
WHILE @i >= 1 BEGIN
SET @v = Convert(int, Substring(@String1, @i, 9)) + Convert(int, Substring(@String2, @i, 9)) + @v / 1000000000
SET @OUTPUT = Right(Replicate('0', 8) + Right(@v, 9), 9) + @OUTPUT
SET @i = @i - 9
END
RETURN @OUTPUT
END
05/12/08 @ 12:04

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)