本篇教程由作者设定未经允许禁止转载。

提前说明,本人的Java水平非常差,我是仿照看C++的方式强硬理解下面的TecTech源码,如果发现有错误,请一定要在评论区指出。

有关的源码部分:源码

我找到了部分相关的函数和方法和类:

public static void run() { // 20k heat cap max!
    new RackComponent(ItemList.Circuit_Primitive.get(1), 1, 4, 0, 500, true); // Primitive Circuit
    new RackComponent(ItemList.Circuit_Basic.get(1), 4, 8, 0, 1000, true); // Basic Circuit
    new RackComponent(ItemList.Circuit_Microprocessor.get(1), 6, 8, 0, 1250, true);
    new RackComponent(ItemList.Circuit_Good.get(1), 6, 9, -.05f, 1500, true); // Good Circuit
    new RackComponent(ItemList.Circuit_Integrated_Good.get(1), 7, 9, -.075f, 1750, true);
    new RackComponent(ItemList.Circuit_Processor.get(1), 8, 9, -.07f, 1800, true);
    new RackComponent(ItemList.Circuit_Parts_Advanced.get(1), 1, 2, -.05f, 2000, true);
    new RackComponent(ItemList.Circuit_Nanoprocessor.get(1), 8, 10, -.09f, 2250, true); // Advanced Circuit
    new RackComponent(ItemList.Circuit_Advanced.get(1), 8, 10, -.1f, 2500, true);
    new RackComponent(ItemList.Circuit_Data.get(1), 9, 1, -.1f, 3000, true); // EV Circuit
    new RackComponent(ItemList.Circuit_Nanocomputer.get(1), 11, 10, -.125f, 3300, true);
    new RackComponent(ItemList.Circuit_Quantumprocessor.get(1), 13, 10, -.15f, 3600, true);
    new RackComponent(ItemList.Circuit_Elite.get(1), 12, 10, -.15F, 3500, true); // IV Circuit
    new RackComponent(ItemList.Circuit_Elitenanocomputer.get(1), 14, 10, -.15F, 4000, true);
    new RackComponent(ItemList.Circuit_Quantumcomputer.get(1), 16, 10, -.15F, 4500, true);
    new RackComponent(ItemList.Circuit_Crystalprocessor.get(1), 18, 10, -.15F, 5000, true);
    new RackComponent(ItemList.Circuit_Master.get(1), 16, 12, -.2F, 5000, true); // LuV Circuit
    new RackComponent(ItemList.Circuit_Masterquantumcomputer.get(1), 16, 13, -.2F, 5100, true);
    new RackComponent(ItemList.Circuit_Crystalcomputer.get(1), 20, 14, -.25F, 5200, true);
    new RackComponent(ItemList.Circuit_Neuroprocessor.get(1), 24, 15, -.3F, 5300, true);
    new RackComponent(ItemList.Circuit_Quantummainframe.get(1), 22, 14, -.3F, 5200, true); // ZPM Circuit
    new RackComponent(ItemList.Circuit_Ultimatecrystalcomputer.get(1), 26, 16, -.3F, 5400, true);
    new RackComponent(ItemList.Circuit_Wetwarecomputer.get(1), 30, 18, -.3F, 5600, true);
    new RackComponent(ItemList.Circuit_Crystalmainframe.get(1), 30, 18, -.35F, 5500, true); // UV Circuit
    new RackComponent(ItemList.Circuit_Wetwaresupercomputer.get(1), 35, 22, -.3F, 5700, true);
    new RackComponent(ItemList.Circuit_Wetwaremainframe.get(1), 38, 25, -.4F, 6000, true); // UHV Circuit

    new RackComponent("IC2:ic2.reactorVent", 0, -1, 10f, 1000, false);
    new RackComponent("IC2:ic2.reactorVentCore", 0, -1, 20f, 2500, false);
    new RackComponent("IC2:ic2.reactorVentGold", 0, -1, 40f, 5000, false);
    new RackComponent("IC2:ic2.reactorVentDiamond", 0, -1, 80f, 10000, false); // 2x oc

    if (Loader.isModLoaded(Reference.DREAMCRAFT)) {
        // GTNH-GT5u circuits
        // these components causes crashes when used with the original GT5u
        new RackComponent(ItemList.NandChip.get(1), 2, 6, 0, 750, true); // Primitive Circuit
        new RackComponent(ItemList.Circuit_Biowarecomputer.get(1), 40, 26, -.35F, 5900, true);
        new RackComponent(ItemList.Circuit_Biowaresupercomputer.get(1), 42, 30, -.4F, 6200, true);
        new RackComponent(ItemList.Circuit_Biomainframe.get(1), 44, 28, -.4F, 6000, true); // UEV Circuit
        new RackComponent(ItemList.Circuit_Bioprocessor.get(1), 34, 20, -.35F, 5800, true);

        new RackComponent("dreamcraft:item.HighEnergyCircuitParts", 3, 2, -.1f, 9001, true);
        new RackComponent("dreamcraft:item.HighEnergyFlowCircuit", 24, 16, -.25f, 10000, true);
        new RackComponent("dreamcraft:item.NanoCircuit", 50, 35, -.45f, 8000, true);
        new RackComponent("dreamcraft:item.PikoCircuit", 64, 40, -.5f, 8500, true);
        new RackComponent("dreamcraft:item.QuantumCircuit", 128, 48, -.6f, 9000, true);
    }

    if (Loader.isModLoaded(Reference.SPARTAKCORE)) {
        // CustomGT5u circuits
        // these components causes crashes when used with the original GT5u
        new RackComponent(ItemList.NandChip.get(1), 2, 6, 0, 750, true); // Primitive Circuit
        new RackComponent(ItemList.Circuit_Biowarecomputer.get(1), 40, 26, -.35F, 5900, true);
        new RackComponent(ItemList.Circuit_Biowaresupercomputer.get(1), 42, 30, -.4F, 6200, true);
        new RackComponent(ItemList.Circuit_Biomainframe.get(1), 40, 28, -.4F, 6000, true); // UHV Circuit
        new RackComponent(ItemList.Circuit_Bioprocessor.get(1), 34, 20, -.35F, 5800, true);
    }

    if (Loader.isModLoaded("OpenComputers")) {
        new RackComponent("OpenComputers:item.oc.Transistor", 0, 1, 0f, 100, true); // Transistor
        new RackComponent("OpenComputers:item.oc.Microchip0", 7, 12, -.05f, 1500, true); // chip t1
        new RackComponent("OpenComputers:item.oc.Microchip1", 18, 20, -.1f, 3000, true); // chip t2
        new RackComponent("OpenComputers:item.oc.Microchip2", 25, 22, -.15f, 4500, true); // chip t3
        new RackComponent("OpenComputers:item.oc.ALU", 10, 15, -.05f, 3000, true); // alu
        new RackComponent("OpenComputers:item.oc.ControlUnit", 25, 18, -.05f, 1500, true); // cu

        new RackComponent("OpenComputers:item.oc.ComponentBus0", 42, 30, -.05f, 1500, true); // bus t1
        new RackComponent("OpenComputers:item.oc.ComponentBus1", 70, 50, -.1f, 3000, true); // bus t2
        new RackComponent("OpenComputers:item.oc.ComponentBus2", 105, 72, -.15f, 4500, true); // bus t3

        new RackComponent("OpenComputers:item.oc.CPU0", 106, 73, -.1f, 1500, true); // cpu t1
        new RackComponent("OpenComputers:item.oc.CPU1", 226, 153, -.15f, 3000, true); // cpu t2
        new RackComponent("OpenComputers:item.oc.CPU2", 374, 241, -.2f, 4500, true); // cpu t3

        new RackComponent("OpenComputers:item.oc.GraphicsCard0", 20, 27, -.1f, 1500, true); // gpu t1
        new RackComponent("OpenComputers:item.oc.GraphicsCard1", 62, 67, -.2f, 3000, true); // gpu t2
        new RackComponent("OpenComputers:item.oc.GraphicsCard2", 130, 111, -.3f, 4500, true); // gpu t3

        new RackComponent("OpenComputers:item.oc.APU0", 350, 234, -.1f, 1500, true); // apu t2
        new RackComponent("OpenComputers:item.oc.APU1", 606, 398, -.2f, 4500, true); // apu t3
        new RackComponent("OpenComputers:item.oc.APU2", 1590, 1006, -.3f, 9000, true); // apu tC
    }
}

public static class RackComponent implements Comparable<RackComponent> {
    private final String unlocalizedName;
    private final float heat, coEff, computation, maxHeat;
    private final boolean subZero;

    RackComponent(ItemStack is, float computation, float heat, float coEff, float maxHeat, boolean subZero) {
        this(getUniqueIdentifier(is), computation, heat, coEff, maxHeat, subZero);
    }

    RackComponent(String is, float computation, float heat, float coEff, float maxHeat, boolean subZero) {
        unlocalizedName = is;
        this.heat = heat;
        this.coEff = coEff;
        this.computation = computation;
        this.maxHeat = maxHeat;
        this.subZero = subZero;
        componentBinds.put(unlocalizedName, this);
        if (DEBUG_MODE) {
            TecTech.LOGGER.info("Component registered: " + unlocalizedName);
        }
    }

    @Override
    public int compareTo(RackComponent o) {
        return unlocalizedName.compareTo(o.unlocalizedName);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof RackComponent) {
            return compareTo((RackComponent) obj) == 0;
        }
        return false;
    }
}

经过分析RackComponent为一个类,指代可以放进量子计算机机箱的组件,类中包含该物品非本地化名称,产热(heat),热效率(CoEff),可产生的算力(Computation),可以忍受的最大温度(maxHeat),subZero暂时没看出来代表什么,但是创建的对象的subZero都是true,实际计算也与subZero的的true和false无关。

接下来找到计算算力的方法:

private int getComputationPower(float overclock, float overvolt, boolean tickingComponents) {
    float computation = 0, heat = 0;
    for (int i = 0; i < mInventory.length; i++) {
        if (mInventory[i] == null || mInventory[i].stackSize != 1) {
            continue;
        }
        RackComponent comp = componentBinds.get(getUniqueIdentifier(mInventory[i]));
        if (comp == null) {
            continue;
        }
        if (tickingComponents) {
            if (this.heat > comp.maxHeat) {
                mInventory[i] = null;
                continue;
            } else if (comp.subZero || this.heat >= 0) {
                heat += (1f + comp.coEff * this.heat / 10000f)
                        * (comp.heat > 0 ? comp.heat * overclock * overclock * overvolt : comp.heat);
                if (overvolt * 10f > 7f + TecTech.RANDOM.nextFloat()) {
                    computation += comp.computation
                            * Math.max(
                                    0,
                                    Math.min(
                                            Math.min(overclock, overvolt + overvolt - 0.25),
                                            1 + TecTech.RANDOM.nextFloat() + (overvolt - 1) - (overclock - 1) / 2));
                }
            }
        } else {
            computation += comp.computation * overclock;
        }
    }
    if (tickingComponents) {
        this.heat += Math.ceil(heat);
    }
    return (int) Math.floor(computation);
}

@Override
public int getInventoryStackLimit() {
    return 1;
}

public int tickComponents(float oc, float ov) {
    if (oc > 3 + TecTech.RANDOM.nextFloat() || ov > 2 + TecTech.RANDOM.nextFloat()) {
        getBaseMetaTileEntity().setToFire();
    }
    overClock = oc;
    overVolt = ov;
    return getComputationPower(overClock, overVolt, true);
}

注意到,正常运行时,传给getComputationPower的参数tickingComponents是true。

TecTech.RANDOM.nextFloat()方法是取(0,1.0)的随机浮点数。

把代码转化成自然语言就是:超频时间倍数>3或者超频电压倍数>2时,机器会烧掉。

每秒遍历单个机箱里面的所有组件,首先计算机箱改变的热量ΔHeat:

对于单个组件,机箱热量改变量ΔHeat=(1+组件的热效率*(当前热量/10000))*ψ

Ψ变量与组件是否产热有关

如果组件产热,Ψ=组件产热*[(超频时间倍数)^2]*(超频电压倍数)

如果组件不产热,Ψ=组件产热

实际上,对于散热片一类,组件产热是负值

理论上总热量改变量ΣΔHeat=Σ(i=1,4) (1+热效率(i)*当前热量/10000)*Ψ(i)

实际上,对ΣΔHeat的向上取整值才是真实改变的热量

然后计算算力的提供量:

首先判断超频电压倍数*10和7+σ的大小关系(σ为(0,1.0)之间的随机浮点数):

如果超频电压倍数*10>7+σ

定义α1=min(超频时间倍数,2*超频电压倍数-0.25)

α2=1+ρ+(超频电压倍数-1)-(超频时间倍数-1)/2       (ρ为(0,1.0)之间的随机浮点数)

α3=min(α1,α2)

α4=max(α3,0)

理论输出算力=内部所有元件可提供的算力总和*α4。

实际输出算力,要对理论输出算力向下取整。

这里说明一下,如果不超频,则超频电压倍数为1,超频时间倍数为1,算力为内部所有元件可提供的算力总和。

另外,量子计算机机箱也会自然散热:

自然散热涉及以下方法:

@Override
public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
    if (aBaseMetaTileEntity.isServerSide()) {
        if (aTick % 20 == MULTI_CHECK_AT) {
            if (heat > 0) {
                float heatC = 0;
                for (int i = 0; i < mInventory.length; i++) {
                    if (mInventory[i] == null || mInventory[i].stackSize != 1) {
                        continue;
                    }
                    RackComponent comp = componentBinds.get(getUniqueIdentifier(mInventory[i]));
                    if (comp == null) {
                        continue;
                    }
                    if (heat > comp.maxHeat) {
                        mInventory[i] = null;
                    } else if (comp.heat < 0) {
                        heatC += comp.heat * (heat / 10000f);
                    }
                }
                heat += Math.max(-heat, Math.ceil(heatC));
            }

            if (heat > 0) {
                heat -= Math.max(heat / 1000, 1);
            } else if (heat < 0) {
                heat -= Math.min(heat / 1000, -1);
            }

            if (heat > 10000) {
                aBaseMetaTileEntity.setToFire();
            } else if (heat > 9000) {
                aBaseMetaTileEntity.setOnFire();
            } else if (heat < -10000) {
                heat = -10000;
            }
        }
    }
}

自然散热涉及两步:

第一步:首先遍历机箱内所有散热组件,热量改变量ΔHeatC=组件产热*当前热量/10000

第一步热量改变量为max(-当前热量,ΔHeatC向上取整)

第一步热量改变后:

如果heat>0

第二步热量改变量为-max(heat/1000,1)

如果heat<0

第二步热量改变量为-min(heat.1000,-1)

了解清楚原理之后,从RackComponent类生成对象的代码中,可以知道对应的某种元件的性质,注意:是先计算算力和热量改变量,再计算自然散热,注意计算的顺序。

判断某种设计是否可行有两种方式:

第一种:建立Heat(t+1)=f(Heat(t))的迭代公式,发现符合GuassSidel迭代法条件,从而判断系数矩阵是否严格对角占优或对称正定,能确定是否收敛。但是缺点是计算量大,而且仍然需要计算出稳定时的热量和最值,因为组件有允许的热量上限,要保证组件不会损毁。

第二种:直接建立方程,求稳定时的Heat值,这种计算较快,但是不能确定是否温度上升到高于Heat之后再降下来的情况,有可能这种情况导致了组件损坏。

下面是用于辅助计算的C++源码,适合超频和不超频的情况的计算某种设计是否可行:(前面忘记提了,overclock大于3或者overvolt大于2,机器会直接起火!)

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<ctime>
#include<windows.h>
using namespace std;
#define OK 1
#define Broken 0
#define GreaterThanTheMaximumValue -1
#define SmallerThanTheMinimumValue -1

class Component{
    private:
    float heat;
    float CoEff;
    float MaxHeat;
    float Computation;
    bool Destroyed;
    public:
    void SetData(float a,float b,float c,float d){
        this->heat=a;
        this->CoEff=b;
        this->MaxHeat=c;
        this->Computation=d;
        this->Destroyed=false;
    }
    float GetHeat(){
        return this->heat;
    }
    float GetCoEff(){
        return this->CoEff;
    }
    float GetMaxHeat(){
        return this->MaxHeat;
    }
    float GetComputation(){
        return this->Computation;
    }
    bool GetStatus(){
        return this->Destroyed;
    }
    void OutPutData(){
        printf("该组件的数据:\n产生热量:%f,热效率:%f,可承受的最大热量:%f,提供的算力:%f,是否已经损坏:%f\n",this->heat,this->CoEff,this->MaxHeat,this->Computation,this->Destroyed);
    }
};
class QuantumComputer{
    public:
    Component Array[4];
    private:
    int MaxHeat;
    int NowHeat;
    int ComponentNumber;
    int OutputComputation;
    float OverVolt;
    float OverClock;
    public:
    void SetMaxHeat(int a){
        this->MaxHeat=a;
    }
    void SetNowHeat(int a){
        this->NowHeat=a;
    }
    int GetNowHeat(){
        return this->NowHeat;
    }
    float GetOverVolt(){
        return this->OverVolt;
    }
    float GetOverClock(){
        return this->OverClock;
    }
   
    int GetOutputComputation(){
        return this->OutputComputation;
    }
    void Initialization(int number,float overvolt,float overclock){
            for(int i=0;i<4;i++){
                this->Array[i].SetData(0,0,10000,0);
            }
            this->ComponentNumber=number;
            this->NowHeat=0;
            this->MaxHeat=10000;
            this->OutputComputation=0;
            this->OverClock=overclock;
            this->OverVolt=overvolt;
           
    }
    void GetComponentData(){
        float num1,num2,num3,num4;
        for(int i=0;i<this->ComponentNumber;i++){
            scanf("%f %f %f %f",&num1,&num2,&num3,&num4);  
            this->Array[i].SetData(num1,num2,num3,num4);
            if(this->OverClock==1&&this->OverVolt==1){
                this->OutputComputation=this->OutputComputation+(int)this->Array[i].GetComputation();
            }
            //printf("%d\n",this->OutputComputation);
        }
       
    }
    void PrintComponentData(){
        for(int i=0;i<4;i++){
            this->Array[i].OutPutData();
        }
    }
    void CalcComputationPowerAndHeat(){
        if(this->OverClock==1&&this->OverVolt==1){
            float ChangeHeat1=0;
            for(int i=0;i<4;i++){
                ChangeHeat1=ChangeHeat1+((float)1+this->Array[i].GetCoEff()*this->NowHeat/(float)10000)*(this->Array[i].GetHeat());
            }
            int change=0;
            change=ceil(ChangeHeat1);
            this->NowHeat=this->NowHeat+change;
            //printf("当前热量:%d\n",this->NowHeat);
           
        }else{
            //没写完的程序 
             //printf("nowheat:%d\n",this->NowHeat);
             srand((unsigned)(time(0)));
             //this->OutputComputation=0;
             float Randomnumber1=static_cast <float> (rand()) / static_cast <float> (RAND_MAX);;
             float f1=min(this->OverClock,(float)2*this->OverVolt-(float)0.25);
             float f2=(float)1+Randomnumber1+(this->OverVolt-(float)1)-((this->OverClock-(float)1)/float(2));
             float f3=min(f1,f2);
             float f4=max((float)0,f3);
             //printf("f4:%f\n",f4); 
             float tempout=0;
             for(int i=0;i<4;i++){
                tempout=tempout+f4*this->Array[i].GetComputation();
             }
             this->OutputComputation=floor(tempout);
             
             float ChangeHeat1=0;
             for(int i=0;i<4;i++){
                if(this->Array[i].GetHeat()>0){
                    ChangeHeat1=ChangeHeat1+(this->Array[i].GetHeat()*this->OverClock*this->OverClock*this->OverVolt)*((float)1+this->Array[i].GetCoEff()*this->NowHeat/(float)10000);
                }else if(this->Array[i].GetHeat()<0){
                    ChangeHeat1=ChangeHeat1+(this->Array[i].GetHeat())*((float)1+this->Array[i].GetCoEff()*this->NowHeat/(float)10000);
                }
             }
             int change=0;
             change=ceil(ChangeHeat1);
             //printf("change:%d\n",change);
             this->NowHeat=this->NowHeat+change;
             //printf("nowheat:%d\n",this->NowHeat);
        }


    }
    void NaturalHeatDissipation(){
        float ChangeHeat2=0;
        if(this->NowHeat>0){
            for(int i=0;i<4;i++){
                if(this->Array[i].GetHeat()<0){
                    ChangeHeat2=ChangeHeat2+this->Array[i].GetHeat()*this->NowHeat/(float)10000;            
                }else{
                    continue;
                }

            }
        }
        //printf("数据:%f",ChangeHeat2);
        int temp1=ceil(ChangeHeat2);
        int NaturalChange=0;
        NaturalChange=max(-this->NowHeat,temp1);
        this->NowHeat=this->NowHeat+NaturalChange;
        if(this->NowHeat>0){
            this->NowHeat=this->NowHeat-max(this->NowHeat/1000,1);
        }else if(this->NowHeat<0){
            this->NowHeat=this->NowHeat-min(this->NowHeat/1000,-1);
        }
        if(this->NowHeat<-10000){
            this->NowHeat=-10000;
        }
        //printf("当前热量:%d\n",this->NowHeat); 

    }

    int GetComponentStatus(){
        for(int i=0;i<4;i++){
            if(this->Array[i].GetMaxHeat()<(float)this->NowHeat||this->NowHeat>this->MaxHeat){
                return Broken;
            }
        }
        if(this->NowHeat>10000){
            return Broken;
        }else{
            return OK;          
        }

    }
};
int main(){
    int judge=0;
    while(true){
    printf("输入1启动运算程序,输入0退出运算程序\n");
    scanf("%d",&judge);
    if(judge==0){
        return 0;
    }else if(judge==1){
        int ComponentNum;
        printf("请输入内部的组件数目:\n");
        scanf("%d",&ComponentNum);
        printf("请输入超频电压级和超频时间级:\n");
        float overclock,overvolt;
        scanf("%f %f",&overvolt,&overclock);
        if(overvolt<0.8){
            printf("错误!不稳定的算力提供!\n");
            continue;
        }else if(overclock>3||overvolt>2){
            printf("错误!机器会烧毁!\n") ;
        }
        printf("请按照发热量(初始热流密度),热效率,最大承受热量,提供算力的顺序输入组件的属性:\n") ;
        QuantumComputer* AComputer=new QuantumComputer;
        AComputer->Initialization(ComponentNum,overvolt,overclock);
        AComputer->GetComponentData();
        //AComputer->PrintComponentData();
        int Status=1;
        int tempdata1;
        int tempdata2;
        for(int j=0;j<6000;j++){
            AComputer->CalcComputationPowerAndHeat();
            if(j%2==0){
                tempdata1=AComputer->GetNowHeat();
            }else if(j%2==1){
                tempdata2=AComputer->GetNowHeat();
            }
            Status=AComputer->GetComponentStatus();
            if(Status==0){
                printf("机箱过热熔毁!\n");
                free(AComputer);
                break;
            }
            if(tempdata1==tempdata2){
                printf("这种摆放方式安全!\n");
                printf("机箱稳定时热量:%d\n",tempdata1);
                printf("提供的算力:%d\n",AComputer->GetOutputComputation());
                free(AComputer);
                break;
            }
            AComputer->NaturalHeatDissipation();        
            }      
        }
    }
}