Thread overview
template bug?
Feb 29, 2008
Denton Cockburn
Feb 29, 2008
Koroskin Denis
Feb 29, 2008
Denton Cockburn
Feb 29, 2008
Koroskin Denis
Feb 29, 2008
Janice Caron
Feb 29, 2008
Marius Muja
Feb 29, 2008
Denton Cockburn
Feb 29, 2008
Bill Baxter
February 29, 2008
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.
February 29, 2008
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>();
}
February 29, 2008
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).
February 29, 2008
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.

February 29, 2008
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 :)
February 29, 2008
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.
February 29, 2008
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?
February 29, 2008
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