ฉันชอบเวกเตอร์มาก พวกเขาดีและรวดเร็ว แต่ฉันรู้ว่าสิ่งนี้เรียกว่าวาลเลย์ ทำไมฉันถึงต้องใช้วาลเลย์แทนเวกเตอร์ ฉันรู้ว่า valarrays มีน้ำตาลประโยค แต่นอกเหนือจากนั้นเมื่อมีประโยชน์
ฉันชอบเวกเตอร์มาก พวกเขาดีและรวดเร็ว แต่ฉันรู้ว่าสิ่งนี้เรียกว่าวาลเลย์ ทำไมฉันถึงต้องใช้วาลเลย์แทนเวกเตอร์ ฉันรู้ว่า valarrays มีน้ำตาลประโยค แต่นอกเหนือจากนั้นเมื่อมีประโยชน์
คำตอบ:
Valarrays (value arrays) มีวัตถุประสงค์เพื่อนำความเร็วของ Fortran มาสู่ C ++ คุณจะไม่ทำตัวชี้แนะเพื่อให้คอมไพเลอร์สามารถตั้งสมมติฐานเกี่ยวกับรหัสและปรับให้ดีขึ้นได้ (เหตุผลหลักที่ Fortran เร็วมากคือไม่มีประเภทตัวชี้ดังนั้นจึงไม่มีนามแฝงของตัวชี้)
วาลเลย์ยังมีคลาสที่อนุญาตให้คุณเชือดมันด้วยวิธีที่ง่ายพอสมควรถึงแม้ว่าส่วนหนึ่งของมาตรฐานอาจใช้งานได้อีกเล็กน้อย การปรับขนาดนั้นเป็นการทำลายและขาดตัววนซ้ำ
ดังนั้นหากเป็นตัวเลขที่คุณใช้งานและความสะดวกสบายไม่ใช่สิ่งสำคัญสำหรับการใช้งาน มิฉะนั้นเวกเตอร์จะสะดวกกว่ามาก
valarray
เป็นเด็กกำพร้าที่เกิดมาผิดที่ผิดเวลา มันเป็นความพยายามในการปรับให้เหมาะสมโดยเฉพาะอย่างยิ่งสำหรับเครื่องที่ใช้สำหรับคณิตศาสตร์หนักเมื่อมันถูกเขียน - โดยเฉพาะโปรเซสเซอร์แบบเวกเตอร์เช่น Crays
สำหรับตัวประมวลผลแบบเวกเตอร์สิ่งที่คุณต้องการทำโดยทั่วไปคือใช้การดำเนินการเดี่ยวกับทั้งอาร์เรย์จากนั้นใช้การดำเนินการถัดไปกับอาร์เรย์ทั้งหมดและต่อไปจนกว่าคุณจะทำทุกสิ่งที่คุณต้องการ
อย่างไรก็ตามถ้าคุณไม่ได้จัดการกับอาร์เรย์ที่มีขนาดค่อนข้างเล็กก็มักจะทำงานได้ไม่ดีกับการแคช ในเครื่องจักรที่ทันสมัยที่สุดสิ่งที่คุณต้องการโดยทั่วไป (เท่าที่จะทำได้) คือการโหลดบางส่วนของอาร์เรย์ทำการดำเนินการทั้งหมดที่คุณกำลังจะทำแล้วย้ายไปยังส่วนถัดไปของอาร์เรย์
valarray
ก็ควรที่จะกำจัดความเป็นไปได้ใด ๆ ของนามแฝงซึ่ง (อย่างน้อยในทางทฤษฎี) ให้คอมไพเลอร์ปรับปรุงความเร็วเนื่องจากมีอิสระมากขึ้นในการจัดเก็บค่าในการลงทะเบียน อย่างไรก็ตามในความเป็นจริงฉันไม่แน่ใจว่าการใช้งานจริงใด ๆ จะได้ประโยชน์จากสิ่งนี้ในระดับที่สำคัญ ฉันสงสัยว่ามันเป็นปัญหาแบบไก่และไข่ - หากไม่มีการสนับสนุนคอมไพเลอร์ก็ไม่ได้รับความนิยมและตราบใดที่มันไม่เป็นที่นิยมก็ไม่มีใครที่จะไปยุ่งกับปัญหาในการทำงานกับคอมไพเลอร์เพื่อสนับสนุน
นอกจากนี้ยังมีอาเรย์ของคลาสเสริมที่ทำให้สับสนเพื่อใช้กับวาลเลย์ คุณจะได้รับslice
, slice_array
, gslice
และgslice_array
จะเล่นกับชิ้นส่วนของvalarray
และทำให้มันทำหน้าที่เหมือนอาร์เรย์หลายมิติ นอกจากนี้คุณยังmask_array
สามารถ "ปิดบัง" การดำเนินการ (เช่นเพิ่มรายการใน x ถึง y แต่เฉพาะในตำแหน่งที่ z ไม่เป็นศูนย์) ในการใช้มากกว่าเล็กน้อยvalarray
คุณต้องเรียนรู้มากมายเกี่ยวกับคลาสเสริมเหล่านี้ซึ่งบางอันค่อนข้างซับซ้อนและไม่มีเอกสารใดที่ดูเหมือน (อย่างน้อยสำหรับฉัน)
ที่บรรทัดล่าง: ในขณะที่มันมีช่วงเวลาของความฉลาดและสามารถทำบางสิ่งบางอย่างสวยอย่างประณีตมีบางเหตุผลที่ดีว่ามันเป็น (และเกือบจะแน่นอนจะยังคงอยู่) ปิดบัง
แก้ไข (แปดปีต่อมาในปี 2560): สิ่งที่กล่าวมาก่อนหน้านี้ล้าสมัยไปแล้วอย่างน้อยก็ระดับหนึ่ง ตัวอย่างหนึ่ง Intel ได้ติดตั้ง valarray รุ่นปรับปรุงสำหรับคอมไพเลอร์ ใช้การรวมประสิทธิภาพการทำงานพื้นฐานของ Intel (Intel IPP) เพื่อปรับปรุงประสิทธิภาพ แม้ว่าการปรับปรุงประสิทธิภาพการทำงานที่แน่นอนไม่ต้องสงสัยแตกต่างกันไปการทดสอบอย่างรวดเร็วกับการแสดงรหัสที่ง่ายรอบ 2: 1 การปรับปรุงในความเร็วเมื่อเทียบกับรหัสเหมือนกันรวบรวมกับการดำเนินงาน "มาตรฐาน" valarray
ของ
ดังนั้นในขณะที่ฉันไม่มั่นใจว่าโปรแกรมเมอร์ C ++ จะเริ่มใช้valarray
ในจำนวนมาก แต่ก็มีบางสถานการณ์ที่สามารถปรับปรุงความเร็วได้
ในระหว่างการสร้างมาตรฐานของ C ++ 98 valarray ได้รับการออกแบบเพื่อให้สามารถคำนวณทางคณิตศาสตร์ได้อย่างรวดเร็ว อย่างไรก็ตามในช่วงเวลาดังกล่าว Todd Veldhuizen ได้ประดิษฐ์เทมเพลตการแสดงออกและสร้างblitz ++และเทคนิคการทำเทมเพลตเมตาดาต้าที่คล้ายกันนั้นได้ถูกประดิษฐ์ขึ้นซึ่งทำให้วาเลย์ล้าสมัยไปแล้ว IIRC ผู้เสนอดั้งเดิมของวาลเรย์ทิ้งมันลงไปครึ่งหนึ่งในมาตรฐานซึ่ง (ถ้าเป็นจริง) ก็ไม่ได้ช่วยเช่นกัน
ISTR ที่เหตุผลหลักที่ไม่ได้ลบออกจากมาตรฐานคือไม่มีใครใช้เวลาในการประเมินปัญหาอย่างละเอียดและเขียนข้อเสนอเพื่อลบออก
อย่างไรก็ตามโปรดจำไว้ว่าทั้งหมดนี้เป็นข่าวลือที่จำได้ไม่ชัด ใช้เวลานี้กับเม็ดเกลือและหวังว่าจะมีคนแก้ไขหรือยืนยันสิ่งนี้
ฉันรู้ว่า valarrays มีน้ำตาลประโยค
ฉันต้องบอกว่าฉันไม่คิดว่ามันstd::valarrays
จะมีน้ำตาลมากนัก ไวยากรณ์แตกต่างกัน แต่ฉันจะไม่เรียกความแตกต่างว่า "น้ำตาล" API นั้นแปลก ส่วนที่อยู่std::valarray
ในภาษาการเขียนโปรแกรม C ++กล่าวถึง API ที่ผิดปกตินี้และความจริงที่ว่าเนื่องจากstd::valarray
s คาดว่าจะได้รับการปรับให้เหมาะสมอย่างสูงสุดข้อความแสดงข้อผิดพลาดใด ๆ ที่คุณได้รับขณะใช้งานนั้นอาจไม่ง่าย
จากความอยากรู้เกี่ยวกับปีที่ผ่านมาผมรับมือกับstd::valarray
std::vector
ฉันไม่มีรหัสหรือผลลัพธ์ที่แม่นยำอีกต่อไป (แม้ว่ามันจะไม่ยากในการเขียนของคุณเอง) การใช้ GCC ฉันได้รับประโยชน์ด้านประสิทธิภาพเพียงเล็กน้อยเมื่อใช้std::valarray
กับคณิตศาสตร์ง่าย ๆ แต่ไม่ใช่สำหรับการปรับใช้ของฉันในการคำนวณค่าเบี่ยงเบนมาตรฐาน (และแน่นอนว่าการเบี่ยงเบนมาตรฐานนั้นไม่ซับซ้อนเท่าที่คณิตศาสตร์ดำเนินไป) ฉันสงสัยว่าการดำเนินงานในแต่ละรายการในขนาดใหญ่( หมายเหตุตามคำแนะนำจากmusiphilฉันจัดการเพื่อให้ได้ประสิทธิภาพที่เหมือนกันเกือบstd::vector
การเล่นที่ดีขึ้นกับแคชกว่าการดำเนินการบนstd::valarray
s vector
และvalarray
)
ในที่สุดฉันตัดสินใจที่จะใช้std::vector
ในขณะที่ใส่ใจกับสิ่งต่าง ๆ เช่นการจัดสรรหน่วยความจำและการสร้างวัตถุชั่วคราว
ทั้งสองstd::vector
และstd::valarray
จัดเก็บข้อมูลในบล็อกที่ต่อเนื่องกัน อย่างไรก็ตามพวกเขาเข้าถึงข้อมูลที่ใช้รูปแบบที่แตกต่างกันและที่สำคัญกว่า API สำหรับการstd::valarray
กระตุ้นให้เกิดรูปแบบการเข้าถึงที่แตกต่างกันกว่า API std::vector
สำหรับ
สำหรับตัวอย่างค่าเบี่ยงเบนมาตรฐานในขั้นตอนเฉพาะฉันจำเป็นต้องค้นหาค่าเฉลี่ยของคอลเลกชันและความแตกต่างระหว่างค่าของแต่ละองค์ประกอบและค่าเฉลี่ย
สำหรับสิ่งที่std::valarray
ฉันทำสิ่งที่ชอบ:
std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> temp(mean, original_values.size());
std::valarray<double> differences_from_mean = original_values - temp;
ผมอาจจะได้รับความฉลาดมากขึ้นด้วยหรือstd::slice
std::gslice
มันเป็นเวลากว่าห้าปีแล้ว
สำหรับstd::vector
ฉันทำบางสิ่งตามแนวของ:
std::vector<double> original_values = ... // obviously, I put something here
double mean = std::accumulate(original_values.begin(), original_values.end(), 0.0) / original_values.size();
std::vector<double> differences_from_mean;
differences_from_mean.reserve(original_values.size());
std::transform(original_values.begin(), original_values.end(), std::back_inserter(differences_from_mean), std::bind1st(std::minus<double>(), mean));
วันนี้ฉันจะเขียนที่แตกต่างกันอย่างแน่นอน หากไม่มีอะไรอื่นฉันจะใช้ประโยชน์จาก lambdas C ++ 11
เป็นที่ชัดเจนว่าโค้ดสองชุดนี้ทำสิ่งที่แตกต่างกัน ตัวอย่างหนึ่งstd::vector
ตัวอย่างจะไม่สร้างคอลเลกชันระดับกลางตามstd::valarray
ตัวอย่าง แต่ผมคิดว่ามันยุติธรรมที่จะเปรียบเทียบพวกเขาเพราะความแตกต่างที่มีการเชื่อมโยงกับความแตกต่างระหว่างและstd::vector
std::valarray
เมื่อฉันเขียนคำตอบนี้ฉันสงสัยว่าการลบค่าขององค์ประกอบจากสองstd::valarray
s (บรรทัดสุดท้ายในstd::valarray
ตัวอย่าง) จะเป็นมิตรกับแคชน้อยกว่าบรรทัดที่สอดคล้องกันในstd::vector
ตัวอย่าง (ซึ่งเกิดขึ้นกับบรรทัดสุดท้ายด้วย)
อย่างไรก็ตามปรากฎว่า
std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> differences_from_mean = original_values - mean;
ทำสิ่งเดียวกันกับstd::vector
ตัวอย่างและมีประสิทธิภาพเกือบเหมือนกัน ในที่สุดคำถามคือสิ่งที่คุณต้องการ API
std::vector
จะเล่นแคชได้ดีกว่าstd::valarray
; พวกเขาทั้งสองจัดสรรบล็อกหน่วยความจำที่ต่อเนื่องกันหนึ่งชุดสำหรับองค์ประกอบ
valarray
ตัวอย่างข้างต้นคุณไม่จำเป็นต้องสร้างtemp
valarray
วัตถุ แต่คุณสามารถทำได้std::valarray<double> differences_from_mean = original_values - mean;
แล้วจากนั้นพฤติกรรมแคชควรจะคล้ายกับvector
ตัวอย่าง (โดยวิธีการถ้าmean
เป็นจริงint
ไม่ได้double
คุณอาจต้องstatic_cast<double>(mean)
.)
valarray
ขอบคุณสำหรับคำแนะนำในการทำความสะอาด ฉันจะต้องดูว่ามันช่วยเพิ่มประสิทธิภาพได้หรือไม่ สำหรับmean
ความเป็นอยู่int
: นั่นเป็นความผิดพลาด ตอนแรกฉันเขียนตัวอย่างโดยใช้int
s แล้วก็รู้ว่าสิ่งmean
นั้นจะห่างไกลจากค่าเฉลี่ยจริงเพราะการตัดทอน แต่ฉันพลาดการเปลี่ยนแปลงที่จำเป็นเล็กน้อยในการแก้ไขรอบแรก
valarray ควรปล่อยให้ความดีของการประมวลผลเวกเตอร์ FORTRAN ถูกับ C ++ อย่างใดการสนับสนุนคอมไพเลอร์ที่จำเป็นไม่เคยเกิดขึ้นจริง
หนังสือ Josuttis มีคำอธิบายที่น่าสนใจ (ดูหมิ่น) ในวาลเลย์ ( ที่นี่และที่นี่ )
อย่างไรก็ตามตอนนี้ Intel ดูเหมือนจะมีการทบทวน valarray ในคอมไพเลอร์รุ่นล่าสุดของพวกเขา (เช่นดูสไลด์ 9 ) นี่คือการพัฒนาที่น่าสนใจเนื่องจากชุดคำสั่ง SIMD SSE แบบ 4 ทางของพวกเขากำลังจะเข้าร่วมโดย 8-way AVX และคำสั่ง Larrabee แบบ 16 ทางและเพื่อประโยชน์ในการพกพามันน่าจะดีกว่าในการเขียนโค้ดด้วยนามธรรม วาลเลย์กว่า (พูด) อินทริน
ฉันพบการใช้งานที่ดีอย่างหนึ่งสำหรับวาลเลย์ มันใช้ valarray เหมือนกับอาร์เรย์ numpy
auto x = linspace(0, 2 * 3.14, 100);
plot(x, sin(x) + sin(3.f * x) / 3.f + sin(5.f * x) / 5.f);
เราสามารถนำไปใช้ด้านบนด้วย valarray
valarray<float> linspace(float start, float stop, int size)
{
valarray<float> v(size);
for(int i=0; i<size; i++) v[i] = start + i * (stop-start)/size;
return v;
}
std::valarray<float> arange(float start, float step, float stop)
{
int size = (stop - start) / step;
valarray<float> v(size);
for(int i=0; i<size; i++) v[i] = start + step * i;
return v;
}
string psstm(string command)
{//return system call output as string
string s;
char tmp[1000];
FILE* f = popen(command.c_str(), "r");
while(fgets(tmp, sizeof(tmp), f)) s += tmp;
pclose(f);
return s;
}
string plot(const valarray<float>& x, const valarray<float>& y)
{
int sz = x.size();
assert(sz == y.size());
int bytes = sz * sizeof(float) * 2;
const char* name = "plot1";
int shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, bytes);
float* ptr = (float*)mmap(0, bytes, PROT_WRITE, MAP_SHARED, shm_fd, 0);
for(int i=0; i<sz; i++) {
*ptr++ = x[i];
*ptr++ = y[i];
}
string command = "python plot.py ";
string s = psstm(command + to_string(sz));
shm_unlink(name);
return s;
}
นอกจากนี้เรายังต้องการสคริปต์ไพ ธ อน
import sys, posix_ipc, os, struct
import matplotlib.pyplot as plt
sz = int(sys.argv[1])
f = posix_ipc.SharedMemory("plot1")
x = [0] * sz
y = [0] * sz
for i in range(sz):
x[i], y[i] = struct.unpack('ff', os.read(f.fd, 8))
os.close(f.fd)
plt.plot(x, y)
plt.show()
มาตรฐาน C ++ 11 บอกว่า:
คลาสอาร์เรย์ของ valarray ถูกกำหนดให้ปราศจากรูปแบบนามแฝงบางรูปแบบดังนั้นจึงช่วยให้การดำเนินการกับคลาสเหล่านี้ได้รับการปรับให้เหมาะสม
ดู C ++ 11 26.6.1-2
ด้วยstd::valarray
คุณสามารถใช้สัญลักษณ์ทางคณิตศาสตร์มาตรฐานเช่นv1 = a*v2 + v3
ออกจากกล่อง นี่เป็นไปไม่ได้สำหรับเวกเตอร์เว้นแต่ว่าคุณจะกำหนดโอเปอเรเตอร์ของคุณเอง
std :: valarray มีไว้สำหรับงานที่เป็นตัวเลขจำนวนมากเช่น Computational Fluid Dynamics หรือ Computational Structure Dynamics ซึ่งคุณมีอาร์เรย์ที่มีล้านรายการบางครั้งมีหลายสิบล้านรายการและคุณวนซ้ำในเวลาเดียวกัน บางทีวันนี้มาตรฐาน :: vector มีประสิทธิภาพเทียบเคียง แต่ประมาณ 15 ปีที่แล้ว valarray เป็นข้อบังคับเกือบหากคุณต้องการเขียนแก้ตัวเลขที่มีประสิทธิภาพ