Ph-苯
本帖最后由 Ph-苯 于 2022-12-9 13:52 编辑

书接上回:暗地里到底没了多少?🧐

大雾

Kotlin (JVM):
控制台输出:280

C++:
控制台输出:2379

经群友提醒,在C++用内联再试了一遍:
控制台输出:1397

经群友和坛友提醒,对第二版C++代码开启O2优化,结果控制台输出变成0了……把循环次数改成0xffffffffffffffff,输出还是0。把第一版C++代码启用O2优化,循环次数也改成0xffffffffffffffff,输出也变成0了。我怀疑这部分代码直接被优化没了。
刚刚发现C++我写的赋值运算符函数是错的,导致其没有赋值。我把x和y都改成非const,并使用默认的赋值运算符函数:
不开O2优化,控制台输出:2484
开O2优化,控制台输出:0
不出所料,O2优化把无副作用的循环给优化掉了……
我把主函数改成这样:
控制台输出第一行:23
O2优化果然了得。

src_resources
本帖最后由 src_resources 于 2022-12-9 13:11 编辑

因为C++是在C语言的基础上引入了很多更先进的语法和功能,因此编译器处理后,因为要转换为与C语言对等的可执行二进制文件,因此可能会塞很多未知的等效代码段进去以达到目的,进而造成不必要的延时。
曾经在Ubuntu上用g++试过一次,加上-S选项看了等效汇编代码后和意想当中的完全是两面,本来一个类似于楼主这样的简单for循环,被g++,只需要一些cmp和jnz等指令就可以实现,硬是被它塞了很多自己的segment,再调用对应的预设代码段来实现。还有很多奇怪的变量名只有编译器自己能懂,我看不懂,像极了IT公司里面看同事代码的样子。

另外楼主也可以尝试开启 -O2 选项,再看看用时是多少。


Ph-苯
src_resources 发表于 2022-12-9 13:10
因为C++是在C语言的基础上引入了很多更先进的语法和功能,因此编译器处理后,因为要转换为与C语言对等的可 ...

开了O2,结果变成0了……改成循环0xffffffffffffffff次,还是0……

w6vDqw
本帖最后由 w6vDqw 于 2022-12-11 11:43 编辑

我的评价是,基于栈操作的语言,和用指针直接操作内存的语言比,这就是找虐。
你觉得C++慢肯定是因为你没做好优化。
粗略看了一眼,这代码C和C++混用,这就没意思了。要用C++就要有C++的样子。

gmc_awa
所以,优化是一点,JE版慢是没有做好算法优化就被BE吊打。BE优化好但是因为渲染龙的遗留问题所以光影直接被集体枪毙()
兼容又是另一个问题了

Ph-苯
w6vDqw 发表于 2022-12-9 13:46
我的评价是,基于数栈操作的语言,和用指针直接操作内存的语言比,这就是找虐。
你觉得C++慢肯定是因为你没 ...

确实,C++开了编译器优化后直接把循环给优化没了,确实快了。

src_resources
Ph-苯 发表于 2022-12-9 13:31
开了O2,结果变成0了……改成循环0xffffffffffffffff次,还是0……

看了一下代码,for循环指定了100000000次,main函数里调用的函数也只进行了简单的加减和移位操作;定义的变量v2i 也只是简单的调用了一下这些运算函数,并未实际使用。
估计是编译器直接把for循环优化了,省去了与v2i变量相关的代码,时间复杂度也直接从O(n)降到了O(1)。

Ph-苯
gmc_awa 发表于 2022-12-9 13:49
所以,优化是一点,JE版慢是没有做好算法优化就被BE吊打。BE优化好但是因为渲染龙的遗留问题所以光影直接被 ...

JE确实很多该有算法的地方都没有,BE就不知道了。

w6vDqw
Ph-苯 发表于 2022-12-9 13:53
确实,C++开了编译器优化后直接把循环给优化没了,确实快了。

那是因为这破玩意被编译器丢到了CPU的L1里面了,所以调用速度超乎你想象。

Ph-苯
src_resources 发表于 2022-12-9 13:55
看了一下代码,for循环指定了100000000次,main函数里调用的函数也只进行了简单的加减和移位操作;定义的 ...

我改了,在最后打印v2i,这样就不会被整个优化掉了。

洞穴夜莺
w6vDqw 发表于 2022-12-9 13:57
那是因为这破玩意被编译器丢到了CPU的L1里面了,所以调用速度超乎你想象。 ...

这段循环确实是被C++编译器直接删掉了,这点可以用-S编译选项编译时看到

洞穴夜莺
w6vDqw 发表于 2022-12-9 13:46
我的评价是,基于数栈操作的语言,和用指针直接操作内存的语言比,这就是找虐。
你觉得C++慢肯定是因为你没 ...

在变量不太多不太大并且没有取地址运算的情况下,Java和C++都是直接在寄存器中运算,并不会操作内存

当然我不知道你在说什么,上面这段代码哪有指针???

w6vDqw
洞穴夜莺 发表于 2022-12-9 14:30
在变量不太多不太大并且没有取地址运算的情况下,Java和C++都是直接在寄存器中运算,并不会操作内存

当然 ...

不直接操作为什么会慢,这是问题。

maikuai2020
java就是比c++快一些

洞穴夜莺
w6vDqw 发表于 2022-12-9 14:33
不直接操作为什么会慢,这是问题。


(见圈出部分)

C++编译器把结果直接在编译期算了出来,然后删除了循环并把结果写进了汇编里,怎么可能不快?



Ph-苯
w6vDqw 发表于 2022-12-9 13:46
我的评价是,基于数栈操作的语言,和用指针直接操作内存的语言比,这就是找虐。
你觉得C++慢肯定是因为你没 ...

什么叫C和C++混用?

Summer_leaves
你可就别吹了java这辈子都不如他爹C语言(不是c++)

Ph-苯
本帖最后由 Ph-苯 于 2022-12-10 13:17 编辑

@w6vDqw 不是说printf比cout更快吗?不过开了O2优化估计也差不多了。

Qhxss
Ph-苯 发表于 2022-12-10 07:02
不是说printf比cout更快吗?不过开了O2优化估计也差不多了。

?大佬为啥自己占楼!

Ph-苯
Qhxss 发表于 2022-12-10 07:07
?大佬为啥自己占楼!

有人用评分回复我,我没法引用他。

Qhxss
Ph-苯 发表于 2022-12-10 07:07
有人用评分回复我,我没法引用他。

那你至少艾特一下吧,你作为版主这样不好吧

Ph-苯
Qhxss 发表于 2022-12-10 11:07
那你至少艾特一下吧,你作为版主这样不好吧

噢,对哦,还可以at,多谢提醒。

w6vDqw
本帖最后由 w6vDqw 于 2022-12-10 17:03 编辑
Ph-苯 发表于 2022-12-10 07:02
@w6vDqw 不是说printf比cout更快吗?不过开了O2优化估计也差不多了。

我的算法也不行。
时间复杂度高达o(16*n),运行完之后优势全无。
也是,我根本就不是很会算法,所以……
  1. //
  2. //  main.c
  3. //  ctest
  4. //
  5. //  Created by Merry on 2022/12/10.
  6. //

  7. #include <stdio.h>
  8. #include <time.h>
  9. void getx(unsigned long long *v){
  10.     *v=*v>>32;
  11. }
  12. //操作指针做位移运算。
  13. void gety(unsigned long long *v){
  14.     *v=*v<<32;
  15. }
  16. //由于直接通过指针操作数据,因此再次操作指针做位移运算。
  17. void plus(unsigned long long *v1,unsigned long long *v2){
  18.     getx(v1);
  19.     getx(v2);
  20.     unsigned long long x=*v1+*v2;
  21.     gety(v1);
  22.     gety(v2);
  23.     unsigned long long y=*v1+*v2;
  24.     *v1=((unsigned long long)x<<32)|y;
  25. }
  26. void minus(unsigned long long *v1,unsigned long long *v2){
  27.     getx(v1);
  28.     getx(v2);
  29.     unsigned long long x=*v1-*v2;
  30.     gety(v1);
  31.     gety(v2);
  32.     unsigned long long y=*v1-*v2;
  33.     *v2=((unsigned long long)x<<32)|y;
  34. }
  35. int main(void){
  36.     int x=1,y=2;
  37.     unsigned long long v,*v1=NULL,*v2=NULL;
  38.     v=((unsigned long long)x<<32|y);
  39.     v2=&v;
  40.     v1=v2;
  41. //  定义数据,做好准备工作。操作指针做位与运算。
  42.     struct timespec ts;
  43.     timespec_get(&ts,TIME_UTC);
  44.     long ms=(ts.tv_nsec/1000000);
  45.     long s=(ts.tv_sec);
  46. //  获取开始时间。
  47.     for(int i=0;i<100000000;i++){
  48.         plus(v1,v2);
  49.         minus(v1,v2);
  50.     }
  51. //  循环一亿次。
  52.     timespec_get(&ts,TIME_UTC);
  53.     long ms1=(ts.tv_nsec/1000000);
  54.     long s1=(ts.tv_sec);
  55. //  获取结束时间。
  56.     printf("%lo\n",ms);
  57.     printf("%lo\n",s);
  58.     printf("%lo\n",ms1);
  59.     printf("%lo\n",s1);
  60. //  打印时间。
  61.     return 0;
  62. }
复制代码

yy297676055

java就是比c++快一些

Qhxss
Ph-苯 发表于 2022-12-10 13:17
噢,对哦,还可以at,多谢提醒。

大哥你可是版主
这都不知道吗

ldk3231589928
az我感觉c语言更快awa   仅代表自己

洞穴夜莺
w6vDqw 发表于 2022-12-10 15:58
我的算法也不行。
时间复杂度高达o(16*n),运行完之后优势全无。
也是,我根本就不是很会算法,所以……

我严重怀疑你没有测试过你plus和minus算出来的值到底对不对
你写的这两个函数都可以优化为
  1. void minus(unsigned long long *v1,unsigned long long *v2){
  2.     *v2=0;
  3. }
复制代码
至于为什么计算结果恒等于零蛋我就懒得给你写证明了

名副其实
Python: 你们继续打架,优化到能有你们这程度的时候已经是几十年后了。
——Python 饮了一口 Java,如是说道

w6vDqw
洞穴夜莺 发表于 2022-12-11 09:40
我严重怀疑你没有测试过你plus和minus算出来的值到底对不对
你写的这两个函数都可以优化为至于为什么计算 ...

是0这个我还是知道的。

jinzhaowei
可以的大佬能不能带带我

Ph-苯
名副其实 发表于 2022-12-11 09:41
Python: 你们继续打架,优化到能有你们这程度的时候已经是几十年后了。
——Python 饮了一口 Java,如是说 ...


Ph-苯
洞穴夜莺 发表于 2022-12-11 09:40
我严重怀疑你没有测试过你plus和minus算出来的值到底对不对
你写的这两个函数都可以优化为至于为什么计算 ...

对哦,我之前还没发现这个函数这么离谱。

teddyxlandlee
名副其实 发表于 2022-12-11 09:41
Python: 你们继续打架,优化到能有你们这程度的时候已经是几十年后了。
——Python 饮了一口 Java,如是说 ...

Groovy:哪天我哪怕能像 Kotlin 一样快我就封神了。

Python 虽然也可以预编译字节码,但毕竟人家是动态语言,恨不得运行时去匹配令牌。
Groovy 同理,好像是所有的令牌都在运行时找(没细研究过,电脑里的groovyc已经吃灰了

洞穴夜莺

建议python 3.15直接负数运行时间

80770407
虽然没看懂

Lucier310
懂了,所以java天下第一(bushi)

Ph-苯
teddyxlandlee 发表于 2022-12-17 20:54
Groovy:哪天我哪怕能像 Kotlin 一样快我就封神了。

Python 虽然也可以预编译字节码,但毕竟人家是动态 ...

kt也不慢吧?

Ph-苯
洞穴夜莺 发表于 2022-12-17 21:42
建议python 3.15直接负数运行时间

其实这是绝对值,触底反弹

Ph-苯
Lucier310 发表于 2022-12-18 01:17
懂了,所以java天下第一(bushi)

还有kt和scala也可以吃到jvm的福利()

teddyxlandlee
Ph-苯 发表于 2022-12-18 01:24
kt也不慢吧?

kt确实不慢,但是总感觉kt生成出的字节码很奇怪,比如会整出一些从来没用过的临时变量(这与inline内部库有关)

Ph-苯
teddyxlandlee 发表于 2022-12-18 07:34
kt确实不慢,但是总感觉kt生成出的字节码很奇怪,比如会整出一些从来没用过的临时变量(这与inline内部库 ...

kt生成的字节码甚至能让ij idea的反编译器报错,这不是一般字节码能做到的。

teddyxlandlee
Ph-苯 发表于 2022-12-18 14:46
kt生成的字节码甚至能让ij idea的反编译器报错,这不是一般字节码能做到的。 ...

害,我手搓的东西照样能崩fernflower
咱就是说,趁早润cfr,有些语法糖能给你反编译出来(foreach, 新的switch-case等)
——然而面对不按套路出牌的kotlinc你还是拿它没办法
——面对proguard优化轰炸,它甚至能给你蹦出几个void declaration
毕竟字节码里一些attribute是vm下不能错的(Code, StackMapTable, ConstantValue……)但有些错了也不要紧(AnnotationDefault, RuntimeInvisibleAnnotation, LocalVariable*Table……),后者是可以用来欺骗反编译器的。

啥?爱用 SWAP?爱用 DUP 和 POP?
fernflower: Object var10000;

6355273
Java不正是C加加的升级版吗?

Ph-苯
teddyxlandlee 发表于 2022-12-18 15:31
害,我手搓的东西照样能崩fernflower
咱就是说,趁早润cfr,有些语法糖能给你反编译出来(foreach, 新的s ...

什么手搓的东西能崩fernflower?我还没搞懂原理。

Ph-苯
6355273 发表于 2022-12-18 15:38
Java不正是C加加的升级版吗?

不是啊,java没有这么宣称过,而且java比c++少了很多特性。

teddyxlandlee
Ph-苯 发表于 2022-12-19 20:06
什么手搓的东西能崩fernflower?我还没搞懂原理。

崩倒不至于,但起码会生成错误得以至于无法编译的代码

最简单的例子:相同的local variable(只要我把变量表属性一扔,就恢复正常)
稍微麻烦一点的:自定义invokedynamic,或者比如把 lcmp 运算结果当 int 使
以及其它 fernflower 不认识的语法糖,虽说不一定能生成错误的代码,但一定会降低可读性——毕竟 fernflower 为数不多的语法糖反编译(如 switch-case String)都是基于 javac 的尿性来的

第一页 上一页 下一页 最后一页