前两天在C#版看到一个计算1000!的帖子说的不错。所以自己写了也写一个java版的,借鉴并改造了一下。希望大家提出宝贵意见,指出改进方案!原贴忘了,不好意思!Bolg:http://blog.csdn.net/luojihaidao/archive/2009/04/13/4068536.aspx/**
* User: luoji
* Date: 2009-4-12
* Time: 10:01:06
*/
public class Factorial {
private final static int MAX_UPON = 100000000;
private final static int MAX_BIT = 8;
public static void main(String[] args) {
long a = System.currentTimeMillis();
System.out.println(Factorial.getValue(100));
long b = System.currentTimeMillis();
System.out.println(b - a);
}
public static String getValue(int n) {
long[] value = getArray(n);
StringBuffer buf = new StringBuffer();
int len = 0;
String sT;
for (int i = value.length - 2; i >= 0; i--) {
sT = String.valueOf(value[i]);
len = MAX_BIT - sT.length();
for (; len > 0 && i != value.length - 2; len--) {
buf.append("0");
}
buf.append(value[i]);
}
return buf.toString();
}
/***
* 用数组来记录数
* @param n
* @return
*/
private static long[] getArray(int n) {
int len = (getBit(n) - 1) / MAX_BIT + 2;
long[] factorAarry = new long[len];
long c;
factorAarry[0] = 1;
int bit = 1, i;
for (; n > 1; n--) {
i = 0;
c = 0;
for (; i < bit; i++) {
long cV = n * factorAarry[i] + c;
factorAarry[i] = cV % MAX_UPON;
c = cV / MAX_UPON;
}
factorAarry[i] = c;
if (c > 0) {
bit++;
}
}
return factorAarry;
}
/***
* 得到n!的位数
* @param n
* @return
*/
private static int getBit(int n) {
double result = 0;
for (int i = 1; i < n; i++) {
result += Math.log10(i);
}
result += 1.5;
return (int) Math.ceil(result);
}
}
* User: luoji
* Date: 2009-4-12
* Time: 10:01:06
*/
public class Factorial {
private final static int MAX_UPON = 100000000;
private final static int MAX_BIT = 8;
public static void main(String[] args) {
long a = System.currentTimeMillis();
System.out.println(Factorial.getValue(100));
long b = System.currentTimeMillis();
System.out.println(b - a);
}
public static String getValue(int n) {
long[] value = getArray(n);
StringBuffer buf = new StringBuffer();
int len = 0;
String sT;
for (int i = value.length - 2; i >= 0; i--) {
sT = String.valueOf(value[i]);
len = MAX_BIT - sT.length();
for (; len > 0 && i != value.length - 2; len--) {
buf.append("0");
}
buf.append(value[i]);
}
return buf.toString();
}
/***
* 用数组来记录数
* @param n
* @return
*/
private static long[] getArray(int n) {
int len = (getBit(n) - 1) / MAX_BIT + 2;
long[] factorAarry = new long[len];
long c;
factorAarry[0] = 1;
int bit = 1, i;
for (; n > 1; n--) {
i = 0;
c = 0;
for (; i < bit; i++) {
long cV = n * factorAarry[i] + c;
factorAarry[i] = cV % MAX_UPON;
c = cV / MAX_UPON;
}
factorAarry[i] = c;
if (c > 0) {
bit++;
}
}
return factorAarry;
}
/***
* 得到n!的位数
* @param n
* @return
*/
private static int getBit(int n) {
double result = 0;
for (int i = 1; i < n; i++) {
result += Math.log10(i);
}
result += 1.5;
return (int) Math.ceil(result);
}
}
请看Blog, 太长贴不出来。
public static void main(String[] args){
System.out.println("请输入求阶乘的数:");//提示用户输入相应的数
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//创建一个字符串暂存区对象br用于存放用户 输入的字符串
String s = null;//创建一String类的对象变量s并赋一空引用
try{
s = br.readLine(); //调用BufferedReader类中的实例方法readLine()来读取br所指的字符串并把引用赋给s
}
catch(IOException e){
e.printStackTrace();
System.out.println("出错了");
} //处理可能出现的异常
int parameter = Integer.parseInt(s); //将字符串转换为整型数据
System.out.println(parameter+"!的结果是:"+jieCheng(parameter));//输出阶乘的结果
System.out.println(parameter+"!的结果尾数中0的个数是:"+weiShuLingGeShu(parameter));//输出阶乘结果尾数0的个数
}
public static int weiShuLingGeShu(int m) {//定义方法求尾数0的个数,返回值为int型
int count=0;
for(int i=1; i<=m; i++){
if(i%25 == 0)//如果100以内的某数含两个因子5,则结果会产生两个0,计数变量count加2
count+=2;
else if(i%5 == 0)//如果100以内的某数只含有一个因子5,则结果会产生一个0,计数变量count加1
count++;
}
return count;//返回求得的尾数0的个数
}
public static double jieCheng(int m){//定义方法求阶乘,返回值为double类型
if(m == 1)
return 1;//1的阶乘的结果是1
else
return m*jieCheng(m-1);//通过递归调用的方法求得阶乘的结果
}
}
long[] factorAarry = new long[len]; 这里的len已经是最小的了。 必须先new 这是已经占了内存了, 在判断是0不是0没有意义了吧。
public class Jc1000 {
public static void main(String[] args) {
BigInteger x = BigInteger.valueOf(1);
for (int i = 2; i <= 1000; i++) {
x = x.multiply(BigInteger.valueOf(i));
}
System.out.println(x);
}
}
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
int n;//阶乘数
void calc(char *p,int n);//计算阶乘数的函数
int getSize(int n);//计算阶乘的位数
void main(){
int size;
printf("n!? n=:");
scanf("%d",&n);
char *p;
size=getSize(n);//计算阶乘的位数
p=(char *)calloc(size,sizeof(char));//根据阶乘的位数分配空间
p[0]=1;//使字符数组初始化,最低位是1,其余全0
calc(p,n);//计算阶乘数的函数
for(int i=size-1;i>=0;i--)
printf("%d",p[i]);
}
int getSize(int n){
double size=1;
for(int i=1;i<=n;i++)//计算阶乘的位数,位数=log1+log2......+logn
size+=log10(i);
return (int)size;
}
void calc(char *p,int n){
double bitcount=1;//定义位数,开始为1位数
int add;
for(int i=2;i<=n;i++){
add=0;
bitcount=bitcount+log10(i);//得到当前位数
for(int j=0;j<bitcount;j++){
add+=i*p[j];//运算
p[j]=add%10;//低位放入数组
add=add/10;//高位参与下次运算
}
}
}
本想飘过,但这个我做过,用C++写的,但思想是可以通用的,贴出来参考参考,我是采用模拟手算的方式来处理的,代码如下: #include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
int n;//阶乘数
void calc(char *p,int n);//计算阶乘数的函数
int getSize(int n);//计算阶乘的位数
void main(){
int size;
printf("n!? n=:");
scanf("%d",&n);
char *p;
size=getSize(n);//计算阶乘的位数
p=(char *)calloc(size,sizeof(char));//根据阶乘的位数分配空间
p[0]=1;//使字符数组初始化,最低位是1,其余全0
calc(p,n);//计算阶乘数的函数
for(int i=size-1;i>=0;i--)
printf("%d",p[i]);
}
int getSize(int n){
double size=1;
for(int i=1;i <=n;i++)//计算阶乘的位数,位数=log1+log2......+logn
size+=log10(i);
return (int)size;
}
void calc(char *p,int n){
double bitcount=1;//定义位数,开始为1位数
int add;
for(int i=2;i <=n;i++){
add=0;
bitcount=bitcount+log10(i);//得到当前位数
for(int j=0;j <bitcount;j++){
add+=i*p[j];//运算
p[j]=add%10;//低位放入数组
add=add/10;//高位参与下次运算
}
}
}
for(int i=1000;i>0;i--)
{
bd = bd.multiply(new BigDecimal(i));
}
System.out.println(bd);
List<Byte> list = new ArrayList<Byte>();
list.add((byte)1);
byte u = 0; //进位用
for (int i=1; i<=n; i++) {
for (int j=list.size()-1; j>=0; j--) {
byte b = list.remove(j);
b = (byte)(i*b + u);
list.add(0, (byte)b%10);
u = (byte)b/10;
}
while (u/10 > 0) {
list.add(0, (byte)u%10);
u /= 10;
}
if (u > 0) {
list.add(u);
}
}
System.out.println(Arrays.toString(list.toArray(new byte[0])));
debug下什么都知道拉
顶
算法有待改进啊,还是写JDK的专家厉害!
初始化Map时先存入一些较常见的,比如10!、100!等等。当要计算1000!,它要先计算999!,以此类推,当算到100!时,
查找Map,刚好有,递归就开始逐级返回!
原来想用list来代替数组的,后来想了想,链表不如数组快
一是数组地址连续,二是数组在栈内存中,比链表的堆内存操作快public static byte[] getNMutiply(int n) {
byte[] b = new byte[]{1};
long u; //计算和进位用
int p, q; //计算长度用
for (int i=2; i<=n; i++) {
p = 0;
q = i;
while (q%10 == 0) { //后面是0的数
p++; //算出0的个数
q /= 10; //去除0后的数
} for (int j=b.length-1; j>=0; j--) { //运算过程
u = (q*b[j] + u);
b[j] = (byte)(u%10);
u /= 10;
} q = (u==0 ? 0 : (""+u).length());
if (p+q > 0) { //长度发生变化的时候
byte[] t = b;
b = new byte[t.length+p+q]; //重建数组
System.arraycopy(t, 0, b, q, t.length); //拷贝原数组
for (int j=0; j<p; j++) { //补齐右边的0
b[t.length+j] = (byte)0;
}
for (int j=q-1; j>=0; j--) { //补齐左边的进位
b[j] = (byte)(u%10);
u /= 10;
}
}
} return b;
}public static void test() {
int n = 1000;
long t1 = System.currentTimeMillis();
byte[] b = getNMutiply(n);
long t2 = System.currentTimeMillis();
System.out.printf("time:%d ms\n", t2-t1);
for (int i=0; i<b.length; i++) {
System.out.print(b[i]);
}
System.out.println();
}
楼主 40765 13922 1360 312 16 0
BigDecimal 50438 15406 1406 344 15 16
BigInteger 54125 16282 1500 344 32 15但是楼主的代码有BUG,楼主可以尝试一下 20000! 和 40000! 阶乘20000! 时
java.lang.ArrayIndexOutOfBoundsException: 9668
定位到 getArray -> factorAarry[i] = c;
20000!的BUG 我周一试,因为我已经知道。就是得到n!的位数不够。 但是数字计数: n!的位数: log2 + .....+logn;
在用Math.log10(i); 计算再相加(数多的时候)出现误差。 大家看看有什么比较精确计算n!的位数的方法!!
BUG修改:private static int getBit(int n) {
double result = 0;
for (int i = 1; i < n; i++) {
result += Math.log10(i);
}
result += 1.5;
return (int) Math.ceil(result);
}
=====》
private static int getBit(int n) {
double result = 0;
for (int i = 1; i <= n; i++) {
result += Math.log10(i);
}
result += 1.5;
return (int) Math.ceil(result);
}
byte[] b = new byte[]{1};
long u = 0; //计算和进位用
int p, q; //计算长度用
for (int i=2; i<=n; i++) {
p = 0;
q = i;
while (q%10 == 0) { //后面是0的数
p++; //算出0的个数
q /= 10; //去除0后的数
} for (int j=b.length-1; j>=0; j--) { //运算过程
u = (q*b[j] + u);
b[j] = (byte)(u%10);
u /= 10;
} q = (u==0 ? 0 : (""+u).length());
if (p+q > 0) { //长度发生变化的时候
byte[] t = b;
b = new byte[t.length+p+q]; //重建数组
System.arraycopy(t, 0, b, q, t.length); //拷贝原数组
for (int j=0; j<p; j++) { //补齐右边的0
b[t.length+j] = (byte)0;
}
for (int j=q-1; j>=0; j--) { //补齐左边的进位
b[j] = (byte)(u%10);
u /= 10;
}
}
} return b;
}测试结果:100 :0
1000:250
10000:24750
import java.math.BigInteger;public class Fac{
public static void main(String[] args)
{
BigInteger pro=new BigInteger("1");
for(int i=1;i<=1000;i++)
{
pro=pro.multiply(new BigInteger(""+i));
}
System.out.println(pro);
}
}