Java比C快2倍(作为C++的子集)

xiv*_*r77 -2 c c++ java optimization performance

下面的代码是一种非常低效的乘法算法.它被写成测试目的.我相信我已经用不同的语言编写了相同的代码.

正下方是运行代码的结果.

OS: Windows 7
language: C (as a subset of C++)

compiler: Visual C++
optimization option: /Ox /Oi /Ot /Oy /GL
running time (seconds): 40 +/- 1

compiler: MinGW/gcc
optimization option: -O3 march=native
running time (seconds): 81 +/- 1

compiler: MinGW/g++
optimization option: -O3 march=native
running time (seconds): 82 +/- 1

language: Java

compiler: Oracle JDK
VM: Oracle JVM
running time (seconds): 18 +/- 1
Run Code Online (Sandbox Code Playgroud)

我相信我在我的C代码中做了一些糟糕的事情,完全优化的编译器无法以任何方式优化.如果有任何大问题请告诉我.我正在计划一个项目,其中有一部分涉及大量的计算.我决定在C中编写这个核心计算部分,但是有了这种结果,我宁可用Java编写所有东西; 它更容易,甚至更快?我仍然相信C,所以如果我的代码中有任何问题,请告诉我.我的期望是Java版本应该慢1.5倍或更慢,但它在某种程度上优于C.

TEST.C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

typedef signed char byte;

typedef struct _Array
{
    byte *data;
    int len;
}
Array;

void new_Array(Array *a, int len)
{
    a->data = (byte *)malloc(len * sizeof(byte));
    a->len = len;
}

void del_Array(Array *a)
{
    free(a->data);
}

typedef struct _BUI
{
    Array num;
    int len;
}
BUI[1];

void new_BUI(BUI b, const char *s)
{
    int len = strlen(s);
    b->len = len;
    new_Array(&b->num, len);
    for (int i = 0; i < len; ++i)
    {
        b->num.data[i] = s[len - i - 1] - '0';
    }
}

void del_BUI(BUI b)
{
    del_Array(&b->num);
}

int BUI_cmp(const BUI a, const BUI b)
{
    if (a->len > b->len)
    {
        return 1;
    }
    if (a->len < b->len)
    {
        return -1;
    }
    for (int i = a->len - 1; i >= 0; --i)
    {
        if (a->num.data[i] > b->num.data[i])
        {
            return 1;
        }
        if (a->num.data[i] < b->num.data[i])
        {
            return -1;
        }
    }
    return 0;
}

#define MAX(A, B) (A > B ? A : B)

void BUI_add(BUI r, const BUI a, const BUI b)
{
    Array c;
    new_Array(&c, MAX(a->len, b->len) + 1);
    memset(c.data, 0, c.len);
    memcpy(c.data, a->num.data, a->len);
    for (int i = 0; i < b->len; ++i)
    {
        c.data[i] += b->num.data[i];
    }
    for (int i = 0; i < c.len - 1; ++i)
    {
        if (c.data[i] >= 10)
        {
            c.data[i + 1] += c.data[i] / 10;
            c.data[i] %= 10;
        }
    }
    del_Array(&r->num);
    r->num = c;
    r->len = c.len;
    for (int i = r->num.len - 1; r->num.data[i--] == 0; --r->len);
}

void BUI_mul(BUI r, const BUI a, const BUI b)
{
    BUI c;
    new_BUI(c, "0");
    {
        BUI one;
        new_BUI(one, "1");
        BUI i;
        new_BUI(i, "0");
        for (; BUI_cmp(i, a) < 0; BUI_add(i, i, one))
        {
            BUI_add(c, c, b);
        }
        del_BUI(one);
        del_BUI(i);
    }
    del_Array(&r->num);
    r->num = c->num;
    r->len = c->len;
}

void BUI_print(BUI b)
{
    for (int i = b->len - 1; i >= 0; --i)
    {
        putchar(b->num.data[i] + '0');
    }
}

int main(void)
{
    BUI a;
    new_BUI(a, "123456789");
    BUI b;
    new_BUI(b, "987654321");
    BUI_print(a);
    fputs(" x ", stdout);
    BUI_print(b);
    fputs(" = ", stdout);
    time_t start_time = clock();
    BUI_mul(a, a, b);
    time_t end_time = clock();
    BUI_print(a);
    del_BUI(a);
    del_BUI(b);
    printf("\nelapsed time: %.3f\n", (double)(end_time - start_time) / CLOCKS_PER_SEC);
    printf("%d %d\n", a->num.len, a->len);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Test.java

import java.util.*;

class BUI
{
    byte[] num;
    int len;

    BUI(String s)
    {
        len = s.length();
        num = new byte[len];
        for (int i = 0; i < len; ++i)
        {
            num[i] = (byte)Character.getNumericValue(s.charAt(len - i - 1));
        }
    }

    int cmp(BUI b)
    {
        if (len > b.len)
        {
            return 1;
        }
        if (len < b.len)
        {
            return -1;
        }
        for (int i = len - 1; i >= 0; --i)
        {
            if (num[i] > b.num[i])
            {
                return 1;
            }
            if (num[i] < b.num[i])
            {
                return -1;
            }
        }
        return 0;
    }

    void add(BUI a, BUI b)
    {
        byte[] c = new byte[Math.max(a.len, b.len) + 1];
        Arrays.fill(c, (byte)0);
        System.arraycopy(a.num, 0, c, 0, a.num.length);
        for (int i = 0; i < b.len; ++i)
        {
            c[i] += b.num[i];
        }
        for (int i = 0; i < c.length - 1; ++i)
        {
            if (c[i] >= 10)
            {
                c[i + 1] += c[i] / 10;
                c[i] %= 10;
            }
        }
        num = c;
        len = c.length;
        for (int i = num.length - 1; num[i--] == 0; --len);
    }

    void mul(BUI a, BUI b)
    {
        BUI c = new BUI("0");
        {
            BUI one = new BUI("1");
            BUI i = new BUI("0");
            for (; i.cmp(a) < 0; i.add(i, one))
            {
                c.add(c, b);
            }
        }
        num = c.num;
        len = c.len;
    }

    void print()
    {
        for (int i = len - 1; i >= 0; --i)
        {
            System.out.print(num[i]);
        }
    }
}


public class Test
{
    public static void main(String[] args)
    {
        BUI a = new BUI("123456789");
        BUI b = new BUI("987654321");
        a.print();
        System.out.print(" x ");
        b.print();
        System.out.print(" = ");
        long start_time = System.currentTimeMillis();
        a.mul(a, b);
        long end_time = System.currentTimeMillis();
        a.print();
        System.out.printf("\nelapsed time: %.3f\n", (end_time - start_time) / 1000.0);
    }
}
Run Code Online (Sandbox Code Playgroud)

utn*_*tim 8

"语言:C(作为C++的子集)".

只是没有.

C不是C++的子集.它们具有通用语法(大部分是C),但大多数运行时检查是不同的(取决于编译器),解释代码的方式不同(在少数情况下),并且为C编写的大多数代码都是非常糟糕的C++.

C++有很多工具可以加速你的算法实现(不确定多少,但如果你正确测量,你肯定会看到变化).

举个简单的例子,使用std :: string作为字符数组.

我正在计划一个项目,其中有一部分涉及大量的计算.我决定在C中编写这个核心计算部分,但是有了这种结果,我宁可用Java编写所有东西;

去吧(也就是说,如果它对你来说更简单,用Java编写).您可以在C中获得更好的性能,就像您可以在Java中获得更好的性能一样.由您决定在优化算法和代码时花费了多少时间和精力.

计算速度不会来自使用优化选项运行编译器 - 实际上,它确实存在,但与算法优化的速度相比,这相对较小.通过在您熟悉的开发工具链中进行优化,然后绊倒您不熟悉的语言,您可以获得更快的速度.

它更容易,甚至更快?我仍然相信C,所以如果我的代码中有任何问题,请告诉我.我的期望是Java版本应该慢1.5倍或更慢,但它在某种程度上优于C.

你的逻辑是有缺陷的.

您编写的比较无法以任何方式代表C和Java之间的速度差异(在C++和Java之间更低).它是比较这两种实现的代表,用不同的语言编译,而不是语言本身.

换句话说,比较这样的两个应用程序,即使它们看起来相同,也不会比较语言(或编译器)的速度.它只是比较两个不同的程序,运行相同算法的不同版本.这是一个特例.

您的C代码已编译.它将在不同的硬件上具有不同的性能特征(例如,两个处理器与四个处理器).

您的java代码是字节编译的.它将在大多数Java VM运行之前进行优化,以最好地匹配您的代码将运行的平台.

最后,您可能在C或C++中比在Java中更积极地进行优化,并且如果您需要编写真正的性能关键代码,那么您可能会获得无法与Java匹配的C或C++代码,因为它将是比运行Java VM本身所需的速度阈值更快.

这种优化虽然在特定情况下分析和优化需要花费大量时间和精力,但大多数应用程序域都不需要它.如果你不知道你是否需要这种性能水平,你可能不会.