www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why does not my program is not running?

reply "Unknow" <Unknow gmail.com> writes:
I'm writed a program for calculating the e number. I can compile 
the source code but when i try run the program, system gives 
'program stopped working' error.

Source code;
"""
// main.d

module main;

import std.file;
import std.conv;

long factorial(long i){
	if (i == 0){
		return 1;
	}else{
		return(i * factorial(i-1));
	}
}

void main(string[] args){
	real *e; e = new real; *e = 0; long *integer; integer = new 
long; *integer = 1;
	for(; *integer <= 100; *integer++){
		*e = (*e) + (*integer / factorial(*integer));
	}
	if(exists("e") != 0)
	{
		std.file.write("e", to!string(*e));
	}else{
		//...
	}
	delete(e); delete(integer);
}
"""
Aug 20 2015
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/20/15 4:31 PM, Unknow wrote:
 module main;

 import std.file;
 import std.conv;

 long factorial(long i){
      if (i == 0){
          return 1;
      }else{
          return(i * factorial(i-1));
      }
 }
Note, this is not going to work. At 21!, long will run out of bits. From https://en.wikipedia.org/wiki/Factorial, 100! is 9.332621544×10^157, requiring 157 *decimal* digits, not to mention the base-2 digits that would be required.
 void main(string[] args){
      real *e; e = new real; *e = 0; long *integer; integer = new long;
 *integer = 1;
There is no need for this, you are making pointers from everything, just declare the variables: real e = 0; long integer = 1;
      for(; *integer <= 100; *integer++){
And here is why you crash. *integer++ means return the value currently pointed at by integer, then increment the POINTER by one. This points at some garbage memory (on my system, it happens to be zeroed, so it didn't crash). Not using pointers will help a lot in this code.
          *e = (*e) + (*integer / factorial(*integer));
The second portion of this calculation is INTEGER math, which means except for 1 / 1, it's going to be 0. What you want is (with new style that doesn't use pointers): e = e + (real(integer) / factorial(integer)); The real(...) casts the result to a real before continuing.
      }
      if(exists("e") != 0)
      {
          std.file.write("e", to!string(*e));
Just want to confirm here, you are writing e only if it *already exists*?
      }else{
          //...
      }
      delete(e); delete(integer);
Without pointers, you would remove these. In addition, you do not need to delete pointers even if you did use them -- D is garbage collected.
 }
-Steve
Aug 20 2015
parent "Unknow" <Unknow gmail.com> writes:
On Thursday, 20 August 2015 at 21:10:27 UTC, Steven Schveighoffer 
wrote:
 On 8/20/15 4:31 PM, Unknow wrote:
 module main;

 import std.file;
 import std.conv;

 long factorial(long i){
      if (i == 0){
          return 1;
      }else{
          return(i * factorial(i-1));
      }
 }
Note, this is not going to work. At 21!, long will run out of bits. From https://en.wikipedia.org/wiki/Factorial, 100! is 9.332621544×10^157, requiring 157 *decimal* digits, not to mention the base-2 digits that would be required.
 void main(string[] args){
      real *e; e = new real; *e = 0; long *integer; integer = 
 new long;
 *integer = 1;
There is no need for this, you are making pointers from everything, just declare the variables: real e = 0; long integer = 1;
      for(; *integer <= 100; *integer++){
And here is why you crash. *integer++ means return the value currently pointed at by integer, then increment the POINTER by one. This points at some garbage memory (on my system, it happens to be zeroed, so it didn't crash). Not using pointers will help a lot in this code.
          *e = (*e) + (*integer / factorial(*integer));
The second portion of this calculation is INTEGER math, which means except for 1 / 1, it's going to be 0. What you want is (with new style that doesn't use pointers): e = e + (real(integer) / factorial(integer)); The real(...) casts the result to a real before continuing.
      }
      if(exists("e") != 0)
      {
          std.file.write("e", to!string(*e));
Just want to confirm here, you are writing e only if it *already exists*?
      }else{
          //...
      }
      delete(e); delete(integer);
Without pointers, you would remove these. In addition, you do not need to delete pointers even if you did use them -- D is garbage collected.
 }
-Steve
Thanks a lot of! Im new to D lang.
Aug 20 2015
prev sibling parent reply anonymous <anonymous example.com> writes:
On Thursday 20 August 2015 22:31, Unknow wrote:

 I'm writed a program for calculating the e number. I can compile
 the source code but when i try run the program, system gives
 'program stopped working' error.
 
 Source code;
 """
 // main.d
 
 module main;
 
 import std.file;
 import std.conv;
 
 long factorial(long i){
 if (i == 0){
 return 1;
 }else{
 return(i * factorial(i-1));
 }
 }
 
 void main(string[] args){
 real *e; e = new real; *e = 0; long *integer; integer = new
 long; *integer = 1;
 for(; *integer <= 100; *integer++){
 *e = (*e) + (*integer / factorial(*integer));
 }
 if(exists("e") != 0)
 {
 std.file.write("e", to!string(*e));
 }else{
 //...
 }
 delete(e); delete(integer);
 }
 """
This has a couple issues. 1) The factorial gets huge quickly. For example, factorial(100) definitely won't fit in a long. It'll wrap around and give wrong results. 2) *integer++ doesn't do what you think it does. The increment is done before the dereference. You could fix this, but: 3) Don't use pointers like that. You really don't need to new reals and longs like that. 4) `*integer / factorial(*integer)` does integer division, which you don't want there. You can multiply with `1.0` (a floating point number) to force floating point division: `*integer * 1.0 / factorial(*integer)`. 5) I'm not sure what you want the `exists` condition to do. The way it is, the file "e" is only (over)written when it exists already. This may not be what you want. Better write it like this: ---- if(exists("e")) { /* Do what you want when the file exists. */ } else { /* Do what you want when the file doesn't exist. */ } ---- 6) Don't use delete unless you know exactly what you're doing (which you don't yet). Here's a cleaned up version of your code: ---- module main; import std.stdio: writeln; long factorial(long i){ if (i == 0){ return 1; }else{ return(i * factorial(i-1)); } } void main(string[] args){ real e = 0; long integer = 1; for(; integer <= 10; integer++){ e = e + integer * 1.0 / factorial(integer); } writeln(e); /* 2.71828 */ } ---- I severely limited the range of integer. I don't know off the top of my head how large you can make it without hitting overflow. I removed the file writing, because I'm not sure if you want to write it only when it doesn't exist, or only overwrite when it does exist.
Aug 20 2015
next sibling parent reply "anonymous2" <a b.cd> writes:
On Thursday, 20 August 2015 at 21:11:07 UTC, anonymous wrote:
 I severely limited the range of integer. I don't know off the 
 top of my head how large you can make it without hitting 
 overflow.

 I removed the file writing, because I'm not sure if you want to 
 write it only when it doesn't exist, or only overwrite when it 
 does exist.
with integer == 66 the factorial overflows and becomes 0 (on my machine) => integer division by 0... The overflow happens at lower values, too.
Aug 20 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 8/20/15 5:15 PM, anonymous2 wrote:
 On Thursday, 20 August 2015 at 21:11:07 UTC, anonymous wrote:
 I severely limited the range of integer. I don't know off the top of
 my head how large you can make it without hitting overflow.
with integer == 66 the factorial overflows and becomes 0 (on my machine) => integer division by 0... The overflow happens at lower values, too.
I did this in my test of his code: long factorial(long i){ if (i == 0){ return 1; }else{ auto r = factorial(i-1); assert(r * i / r == i, i.to!string); return r * i; } } And it printed 21 for the exception. 20! fits in a long, 21! doesn't. -Steve
Aug 20 2015
prev sibling parent "Dominikus Dittes Scherkl" writes:
On Thursday, 20 August 2015 at 21:15:36 UTC, anonymous2 wrote:
 On Thursday, 20 August 2015 at 21:11:07 UTC, anonymous wrote:
 I severely limited the range of integer. I don't know off the 
 top of my head how large you can make it without hitting 
 overflow.

 I removed the file writing, because I'm not sure if you want 
 to write it only when it doesn't exist, or only overwrite when 
 it does exist.
with integer == 66 the factorial overflows and becomes 0 (on my machine) => integer division by 0... The overflow happens at lower values, too.
66! has 2 64times as prime-factor, so a long becomes zero at that point. The overflow occures long ago (at 21!), but with 66! if becomes obvious, because you get a division by zero error.
Aug 21 2015
prev sibling parent anonymous <anonymous example.com> writes:
On Thursday 20 August 2015 23:11, anonymous wrote:

 2) *integer++ doesn't do what you think it does. The increment is done
 before the dereference. You could fix this, but:
I got that one wrong. Steven Schveighoffer has it right. The pointer is incremented after the currently pointed-to value is returned. Still not what was expected, of course.
Aug 20 2015