本篇教程由作者设定未经允许禁止转载。
提前说明,本人的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();
}
}
}
}