设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 3102|回复: 21
打印 上一主题 下一主题

[通用发布] 【C语言发布】非齐次线性方程组的解……(上)

[复制链接]

Lv1.梦旅人

梦石
0
星屑
121
在线时间
1914 小时
注册时间
2013-9-2
帖子
1770

剧作品鉴家

跳转到指定楼层
1
发表于 2016-9-16 18:26:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 zaiy2863 于 2016-9-17 14:08 编辑

@RyanBern 的指导下随手写了一发、、、……
但是最高只能支持到阶数n=51 再继续增加会有误差的说(๑• . •๑)
编译器gcc

基本思路是采用高斯消元法、的说
……测试函数保留着,但是已经注释掉了

以及、最喜欢@⑨姐姐 了……
希望⑨姐姐不要嫌弃叶子太笨……(๑• . •๑)

代码如下:
C 代码复制
  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <stdlib.h>
  4. void test_mat_gen(int n, double *a, double *b);
  5. int main(){
  6.         //输入待计算的矩阵  
  7.         int n;
  8.         scanf("%d",&n);
  9.          //n = 84;
  10.         double A[n*n];//第j列第i行写作A[j*n + i]
  11.         int i,j,k;
  12.         double b[n+1];
  13.         for(i = 0; i<n*n; i++){
  14.                 A[i] = 0.0;
  15.         }
  16.         for(i = 0; i<n+1; i++){
  17.                 b[i] = 0.0;
  18.         }
  19. //test_mat_gen(n, A, b);//测试函数
  20.         //录入
  21.         for(i = 0; i<n*n; i++){
  22.                 scanf("%lf", &A[i]);
  23.         }
  24.         for(i = 0; i<n; i++){
  25.                 scanf("%lf", &b[i]);
  26.         }
  27.         //高斯消元法:对于每个i,j
  28.         double q;
  29.         k = 0;
  30.         for(k = 0; k<n; k++){//从A[k*n +k]开始计数
  31.                 for(j = k+1; j<n; j++){//列增加,以j计数
  32.                 q =(double) A[j*n + k]/ A[k*n + k] ;
  33.                 //if(q)printf("%f\n", q);
  34.                         for(i = 0; i<n; i++){//j为列 i为行 则固定行数,对列数增加
  35.                                 A[j*n + i] -= q * A[k*n + i];
  36.                         }
  37.                         b[j] -= q* b[k];
  38.                 }
  39.         }
  40.  
  41.         //得出结果
  42.          for(i = n-1; i>=0; i--){//对于每个b[i],减去已经算得的b[i],用于存储x[i]值
  43.                  for(j = i+1; j>i; j--){
  44.                  b[i] -= b[j]*A[i*n + j];//b[i]写在第i行        
  45.                  }
  46.                  b[i] /= A[i * n + i];
  47.          }
  48.  
  49.          for(i = 0; i<n; i++){
  50.                 printf("%f\n", b[i]);
  51.         }
  52.  
  53. return 0;       
  54. }
  55. /*
  56. void test_mat_gen(int n, double *a, double *b){
  57.         int i;
  58.         for(i = 0; i<n; i++){
  59.                 a[i * n + i] = 6;
  60.                 if(i < n - 1){
  61.                         a[(i+1)*n + i] = 1;
  62.                 }
  63.                 if(i){
  64.                         a[(i-1)*n + i] = 8;
  65.                 }
  66.                 if(i == 0){
  67.                         b[i] = 14;
  68.                 }else if(i == n-1){
  69.                         b[i] = 7;
  70.                 }else{
  71.                         b[i] = 15;
  72.                 }
  73.         }
  74.  
  75. }
  76. */

评分

参与人数 3星屑 +141 收起 理由
浮云半仙 + 15 塞糖
天使喝可乐 + 66 塞糖
寒冷魔王 + 60 塞糖

查看全部评分

RM新人,尚在摸索熟悉软件中。对您的指教十分感谢。(鞠躬
RM的新手教程新手教程新手教程
喵雪大触的像素绘画教程

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

2
发表于 2016-9-16 19:01:24 | 只看该作者
前排。坐等更新。

另外这代码还得注意程序规范的问题,比如声明的时候通常不加变量名字,只说类型。
还有这个写法到底是啥意思
C 代码复制
  1. scanf("%.0f\t", &[i]);

点评

单纯地写错了而已(捂脸逃)  发表于 2016-9-16 21:46
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1024
在线时间
1389 小时
注册时间
2010-8-9
帖子
3471
3
发表于 2016-9-17 01:17:50 | 只看该作者
本帖最后由 寒冷魔王 于 2016-9-17 01:45 编辑

哇,小叶子也做这个了呢~
前排支持!

另外,看你使用一维数组作为矩阵处理的话,可以考虑写一些对应的函数哦~
  1. double A[n*n];//第j列第i行写作A[j*n + i]
  2. // 写成:
  3. double getMatrixElement(double matrix[], int i, int j) // 按照习惯交换j和i的位置,根据你的注释,j表示列,i表示行,数学上的习惯是a(i j)
  4. {
  5.     return matrix[j*n + i];
  6. }
  7. void setMatrixElement(double matrix[], int i, int j, double element)
  8. {
  9.     matrix[j*n + i] = element;
  10. }
复制代码

用法:
double A[n * n];
v = getMatrixElement(A, i, j);
setMatrixElement(A, i, j, v);
这样写不容易出错,只要把i和j的位置对应好就行了~


============================以下内容可以无视==============================

小叶子你的写法呢,double A[n*n]; 其实是C99的标准,这个n是变量。
如果要用C++(兼容C89但不兼容C99)编译呢,最好写成
  1. double *A = (double*)calloc(n*n, sizeof(double));  // 用calloc的话不用手动清零。
复制代码

当然需要用完后free才行。

建议使用struct来表示Matrix
  1. struct Matrix
  2. {
  3.     double *data;
  4. };
复制代码


用struct Matrix代替double[]的好处是不会和其他的double[]弄混,而且能够直接复制struct Matrix哦~
  1. void initMatrix(struct Matrix *matrix, int n)
  2. {
  3.     matrix->data = (double*)calloc(n*n, sizeof(double));
  4. }
  5. void freeMatrix(struct Matrix *matrix)
  6. {
  7.     free(matrix->data);
  8. }
  9. double getMatrixElement(struct Matrix *matrix, int i, int j)
  10. {
  11.     return matrix->data[j*n + i];
  12. }
  13. void setMatrixElement(struct Matrix *matrix, int i, int j, double element)
  14. {
  15.     matrix->data[j*n + i] = element;
  16. }
复制代码

使用方法是
struct Matrix A;
initMatrix(&A, n);              // 初始化
v = getMatrixElement(&A, i, j); // 获取 v = A(i j)
setMatrixElement(&A, i, j, v);  // 设置 A(i j) = v
freeMatrix(&A);                 // 释放


如果在struct Matrix内加个变量储存矩阵大小,还可以顺便检查其访问元素是否越界。
  1. struct Matrix
  2. {
  3.     double *data;
  4.     int size;
  5. };
复制代码

更好一些的代码:
  1. void initMatrix(struct Matrix *matrix, int n)
  2. {
  3.     matrix->data = (double*)calloc(n*n, sizeof(double));
  4.     matrix->size = n;
  5. }
  6. void freeMatrix(struct Matrix *matrix)
  7. {
  8.     free(matrix->data);
  9. }
  10. double getMatrixElement(struct Matrix *matrix, int i, int j)
  11. {
  12.     assert(i >= 0 && matrix->size > i && j >= 0 && matrix->size > j);
  13.     return matrix->data[j*n + i];
  14. }
  15. void setMatrixElement(struct Matrix *matrix, int i, int j, double element)
  16. {
  17.     assert(i >= 0 && matrix->size > i && j >= 0 && matrix->size > j);
  18.     matrix->data[j*n + i] = element;
  19. }
复制代码

其中,getMatrixElement和setMatrixElement新增的assert会在Debug模式下检查不符合表达式的错误,自动结束程序。
它检查的是 i 和 j 在 [0,matrix->size) 的区间内。
assert用于检查编程错误,比如循环时不小心多了1次,越界了之类的。不要用assert判断程序需要处理的错误。

这个assert在非Debug模式下会去除,GCC中,使用NDEBUG用于去除assert。
因为assert会去除,所以不要在assert中写能够改变程序状态的代码,如
assert(i++);
这会导致程序的行为不一致。

点评

这样的set/get没必要分开写,见回复  发表于 2016-9-18 03:25

评分

参与人数 1星屑 +128 收起 理由
zaiy2863 + 128 谢谢 不过后面的内容几乎看不懂呢.

查看全部评分

SRPG on RM 项目研发组 正式成立。目前SRPG·RMVA系统进度88.8%。SMRC Kernel 进度90%
↖(^ω^)↗热烈庆祝~SMRC Ver5.1 SRPG战棋地图移动范围生成脚本正式发布~~
-----------------------------------------------------------------------------------------
SMRC具有高性能、高兼容、定制自由、使用方便的特点。
1.性能,100移动力轻松算出,无压力;
2.兼容,RGSS1-3通吃,效率保证;
3.支持移动形状定制,支持4方位、6方位、正方形或其他任意有移动规律的形状;
4.可以充当高性能寻路来使用。
【链接点此】
-----------------------------------------------------------------------------------------
【2016/01/06更新 | 改版】RM脚本编辑器Gemini
-----------------------------------------------------------------------------------------
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

4
发表于 2016-9-18 00:01:11 | 只看该作者
本帖最后由 RyanBern 于 2016-9-18 00:02 编辑
寒冷魔王 发表于 2016-9-17 01:17
哇,小叶子也做这个了呢~
前排支持!


首先,是因为是叶子所以回复这么认真么/w\

如果要用C++(兼容C89但不兼容C99)编译呢,最好写成...

其实我早就跟叶子说了我不建议这样,但是谁让它是一个 C 语言程序并且自动打开 gcc 的 c99 标准呢……似乎我好像永远活在了 ANSI C 标准中无法自拔。

另外“使用C++编译”似乎是个不准确的说法呢……

用struct Matrix代替double[]的好处是不会和其他的double[]弄混,而且能够直接复制struct Matrix哦~

你确定?除非你显式写出复制的函数,否则是绝对不能这样“直接”复制的。

如果单纯考虑不弄混的话,可以直接定义一个类型,这样就不容易混了。
C 代码复制
  1. typedef double* MatElePr;


另外从你的回帖里我能看出你尽量把程序做得面向对象一点,于是想方设法去写 Constructor Destructor 等东西。其实我在群里是这样教叶子的:不许用 struct,不许有面向对象的思维,给我用纯指针弄。

看来我的反面向对象思维越来越严重了。不过,有关的高性能的数学库确实不会考虑这些封装呢。

点评

当然是因为小叶子啦/w\。  发表于 2016-9-18 00:05

评分

参与人数 1星屑 +128 收起 理由
zaiy2863 + 128 谢谢rb君……

查看全部评分

回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1024
在线时间
1389 小时
注册时间
2010-8-9
帖子
3471
5
发表于 2016-9-18 00:50:18 | 只看该作者
本帖最后由 寒冷魔王 于 2016-9-18 01:11 编辑
RyanBern 发表于 2016-9-18 00:01
首先,是因为是叶子所以回复这么认真么/w\


/w\感谢您的回复,看到小叶子这么认真所以激动的有些忘乎所以了呢~

关于
你确定?除非你显式写出复制的函数,否则是绝对不能这样“直接”复制的。

我是确定的,刚刚测试了一下(gcc -std=c99)



看来我没记错,是可以直接复制的。(应该是新标准?好像是当年看C++Primer里面写的,具体出处我也忘了)

不能弄混是指传递参数的时候啦,用typedef定义的话传递参数还是会弄混的(当然R君要是不用函数的话确实能够达到效果)

另外呢,可能是我经常用C++的缘故,所以用C的话有些面向对象了呢(/w\)
哎嘿嘿,正统的面向过程C语言确实不喜欢面向对象什么的。。
其实因为我用到了calloc和free,这种构建使用函数来管理是更方便及安全的。(比如只是init而忘了free,导致内存泄漏,也可以通过在函数内部加输出判断是否泄漏)
同时,关于您对性能的顾虑,我觉得您多虑了。
现代编译器(比如小叶子手头上的gcc(目测5.1以上))的话,能够正确处理这些问题,自动inline什么的,编译出来的效果可以媲美C语言的宏。
而且inline函数可以进行参数检查,可以预防很多编程错误。要比直接写效果更好。
哦对,inline貌似是C99标准。。。

我觉得初次编写的时候,这个安全性要首先保证。这样编写和修改都很简单。
编写成型以后再做优化(比如内嵌汇编神马的),这样可以避免过早优化。

其实我写的时候就想,要是直接用C++的RAII多方便。
如果使用C++的话,我觉得基于RAII的内存管理和适当的封装对于编写清晰安全并且高效的代码很有帮助。像小叶子写的A[j*n + i],改成A.get(i, j)什么的,我觉得可读性就上升许多,也易于维护。不需要手动调用free什么的,也减少了内存泄漏的可能性。

所以说适当的封装是有好处的,R君可能需要常年编写这种高性能的程序,对这方面比较敏感。不过我觉得这种损失目前来说还是可以忽略的。

总之!
像R君这样的数学专业人士、人品保障的前辈,能给出专业意见、提出人生建议,呵护小叶子健康快乐成长,我对您是很放心的。
SRPG on RM 项目研发组 正式成立。目前SRPG·RMVA系统进度88.8%。SMRC Kernel 进度90%
↖(^ω^)↗热烈庆祝~SMRC Ver5.1 SRPG战棋地图移动范围生成脚本正式发布~~
-----------------------------------------------------------------------------------------
SMRC具有高性能、高兼容、定制自由、使用方便的特点。
1.性能,100移动力轻松算出,无压力;
2.兼容,RGSS1-3通吃,效率保证;
3.支持移动形状定制,支持4方位、6方位、正方形或其他任意有移动规律的形状;
4.可以充当高性能寻路来使用。
【链接点此】
-----------------------------------------------------------------------------------------
【2016/01/06更新 | 改版】RM脚本编辑器Gemini
-----------------------------------------------------------------------------------------
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv2.观梦者 (禁止发言)

梦石
0
星屑
653
在线时间
3774 小时
注册时间
2011-2-26
帖子
1839

开拓者

6
发表于 2016-9-18 01:46:35 | 只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

7
发表于 2016-9-18 08:43:31 | 只看该作者
本帖最后由 RyanBern 于 2016-9-18 09:00 编辑
寒冷魔王 发表于 2016-9-18 00:50
/w\感谢您的回复,看到小叶子这么认真所以激动的有些忘乎所以了呢~

关于


C 代码复制
  1. struct A1{
  2.   double data[5];
  3. };

C 代码复制
  1. struct A2{
  2.   double *data;
  3. };


下面两个有本质的区别啊,不要把它们当成一样的了喂!

C 代码复制
  1. printf("%d %d\n", sizeof(struct A1), sizeof(struct A2));


这样会看到很明显的不同。

概况来说,如果是动态分配的内存,是绝对不可以这样玩的。

C 代码复制
  1. struct A{
  2.   double *data;
  3. };
  4.  
  5. int main(int argc, char **argv){
  6.   struct A a1, a2;
  7.   /* suppose we call 'constructors' for a1 and a2 */
  8.   init(&a1, n); init(&a2, n);
  9.   a2 = a1; /* the problem occurs ! */
  10.   a1.data[0] = 1; /* then what is a2.data[0]? */
  11.   /* suppose we call 'destructors' for a1 and a2 */
  12.   finalize(&a1); finalize(&a2); /* core dumped !*/
  13.   return 0;
  14. }


写得有点仓促,但是我觉得意思应该表示清楚了。

点评

像这种指针共享的问题,C语言的话我真没思考过怎么处理,不过C++的话有引用计数智能指针shared_ptr啥的,所以一般不用担心。  发表于 2016-9-18 10:42
/w\ 我说的是“用struct Matrix代替double[]”啦 233  发表于 2016-9-18 10:34
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
2240
在线时间
325 小时
注册时间
2012-5-8
帖子
99

开拓者

8
发表于 2016-9-18 10:40:54 | 只看该作者
我看了半天也没有想通,为什么在RPGMaker发布这么专业的C语言技术文档
能问一句,这个是做什么用的?用在哪里?难道RPGMaker里还能用C语言吗?

点评

C的话,MV可以用emscripten, XPVXVA可以用在下的RGSSInline或MSF的metasm, what's the problem  发表于 2016-9-18 13:58
因为先前有个帖子发Ruby版的非齐次线性方程组的求解。。这个是LZ发的对应C版本。。  发表于 2016-9-18 10:51
回复 支持 反对

使用道具 举报

Lv5.捕梦者 (暗夜天使)

只有笨蛋才会看到

梦石
1
星屑
20995
在线时间
9336 小时
注册时间
2012-6-19
帖子
7107

开拓者短篇九导演组冠军

9
发表于 2016-9-18 13:32:28 | 只看该作者
condir 发表于 2016-9-18 10:40
我看了半天也没有想通,为什么在RPGMaker发布这么专业的C语言技术文档
能问一句,这个是做什么用的 ...

因为真正能用在 RPG Maker 里的东西都发布到水区去了
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1774
在线时间
950 小时
注册时间
2012-7-5
帖子
245
10
发表于 2016-11-17 14:43:13 | 只看该作者
本帖最后由 浮云半仙 于 2016-11-17 17:08 编辑

膝行而前,莫能仰视

点评

嘤嘤嘤为什么要把这个破轮子顶起来  发表于 2016-11-17 17:38
tan(pi/2)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-5-4 21:11

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表