www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - template bug?

reply Denton Cockburn <diboss hotmail.com> writes:
In DMD 2.011

import std.stdio;

template factorial(real n)
{
	static if (n == 1)
		const factorial = 1;
	else const factorial = n * factorial!(n - 1);
}

void main()
{
	writefln(factorial!(5));
}

produces: -3.10504e+231

when the template is changed to accept an int instead of a real, it
produces the right output: 120

What's the cause of this?

Note: in 1.027, the version accepting a real still produces the correct
output of 120.
Feb 28 2008
next sibling parent reply "Koroskin Denis" <2korden+dmd gmail.com> writes:
On Fri, 29 Feb 2008 08:35:02 +0300, Denton Cockburn <diboss hotmail.com>=
  =

wrote:

 In DMD 2.011

 import std.stdio;

 template factorial(real n)
 {
 	static if (n =3D=3D 1)
 		const factorial =3D 1;
 	else const factorial =3D n * factorial!(n - 1);
 }

 void main()
 {
 	writefln(factorial!(5));
 }

 produces: -3.10504e+231

 when the template is changed to accept an int instead of a real, it
 produces the right output: 120

 What's the cause of this?

 Note: in 1.027, the version accepting a real still produces the correc=

 output of 120.

Seems like a bug to mee, too. This produces incorrect output as well: template factorial(real n) { const real factorial =3D 1; } void main() { writefln(factorial!(5)); } In C++, one cannot use real as a template parameter. The following code = = won't compile, although the code looks harmless :) template<float t> class SomeClass { static const float someValue =3D t; } void main() { float value =3D SomeClass<5.0f>::someValue; // 5.0f expected } However this one can easily instanciate as much templates, at it wishes = = because of rounding error on floating point arithmetics: template<float t> float factorial() { if (t =3D=3D 1) { ///< this condition might never be satisfied return 1; } else { return t*factorial(t-1); } } int main() { float t1 =3D factorial<5.0f>(); float t2 =3D factorial<5.1f>(); }
Feb 29 2008
parent reply Denton Cockburn <diboss hotmail.com> writes:
On Fri, 29 Feb 2008 12:58:26 +0300, Koroskin Denis wrote:

 On Fri, 29 Feb 2008 08:35:02 +0300, Denton Cockburn <diboss hotmail.com>  
 wrote:
 
 In DMD 2.011

 import std.stdio;

 template factorial(real n)
 {
 	static if (n == 1)
 		const factorial = 1;
 	else const factorial = n * factorial!(n - 1);
 }

 void main()
 {
 	writefln(factorial!(5));
 }

 produces: -3.10504e+231

 when the template is changed to accept an int instead of a real, it
 produces the right output: 120

 What's the cause of this?

 Note: in 1.027, the version accepting a real still produces the correct
 output of 120.

Seems like a bug to mee, too. This produces incorrect output as well: template factorial(real n) { const real factorial = 1; } void main() { writefln(factorial!(5)); } In C++, one cannot use real as a template parameter. The following code won't compile, although the code looks harmless :) template<float t> class SomeClass { static const float someValue = t; } void main() { float value = SomeClass<5.0f>::someValue; // 5.0f expected } However this one can easily instanciate as much templates, at it wishes because of rounding error on floating point arithmetics: template<float t> float factorial() { if (t == 1) { ///< this condition might never be satisfied return 1; } else { return t*factorial(t-1); } } int main() { float t1 = factorial<5.0f>(); float t2 = factorial<5.1f>(); }

D template parameters can be: * types * integral values * floating point values * string literals * templates * or any symbol http://www.digitalmars.com/d/2.0/templates-revisited.html I guess this is a bug.
Feb 29 2008
parent "Koroskin Denis" <2korden+dmd gmail.com> writes:
On Fri, 29 Feb 2008 18:15:18 +0300, Denton Cockburn <diboss hotmail.com>  
wrote:
 [snip]

D template parameters can be: * types * integral values * floating point values * string literals * templates * or any symbol http://www.digitalmars.com/d/2.0/templates-revisited.html I guess this is a bug.

I din't say a thing about (in)correctness of this code. In fact, I was talking about C++! However, you should use this feature with care :)
Feb 29 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 29/02/2008, Denton Cockburn <diboss hotmail.com> wrote:
  template factorial(real n)

Forgive me, but factorial is not defined for real numbers. The domain of factorial is the positive integers only. Of course, if you want to write a compile-time gamma function! ... :-) (I know, I know - it's a bug report, not a math lesson. I'll shut up now).
Feb 29 2008
prev sibling parent reply Marius Muja <mariusm cs.ubc.ca> writes:
Because of the nature of floating point numbers, you shouldn't use 
equality(==) to compare floating point numbers.

Instead of n==1 you should write something like abs(n-1)<eps (where eps 
is a small number)

Denton Cockburn wrote:
 In DMD 2.011
 
 import std.stdio;
 
 template factorial(real n)
 {
 	static if (n == 1)
 		const factorial = 1;
 	else const factorial = n * factorial!(n - 1);
 }
 
 void main()
 {
 	writefln(factorial!(5));
 }
 
 produces: -3.10504e+231
 
 when the template is changed to accept an int instead of a real, it
 produces the right output: 120
 
 What's the cause of this?
 
 Note: in 1.027, the version accepting a real still produces the correct
 output of 120.

Feb 29 2008
next sibling parent Denton Cockburn <diboss hotmail.com> writes:
On Fri, 29 Feb 2008 10:46:23 -0800, Marius Muja wrote:

 Because of the nature of floating point numbers, you shouldn't use 
 equality(==) to compare floating point numbers.
 
 Instead of n==1 you should write something like abs(n-1)<eps (where eps 
 is a small number)
 

That wouldn't explain why it works in 1.027 and not 2.011. The next thing, it doesn't explain why: template factorial(real n) { static if (n == 1.0L) const real factorial = 1.0L; else const real factorial = 5.0L; } void main() { writefln(factorial!(5.0L)); } which is using full real comparisons, and in either case should execute the else even if it doesn't equate, produces an output of -1.49167e-154. 1.027 produces the correct output of 5 again. P.S. Isn't that how == is defined for floating point numbers already? If not, shouldn't it be that way?
Feb 29 2008
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Marius Muja wrote:
 Because of the nature of floating point numbers, you shouldn't use 
 equality(==) to compare floating point numbers.
 
 Instead of n==1 you should write something like abs(n-1)<eps (where eps 
 is a small number)

It's true generally, but integers (up to a point) have an exact representation in floating point. Multiplying exact real integers by exact real integers will yield exact real integers as long as you don't overlflow the mantissa. -bb
Feb 29 2008