Cập nhật: đọc đến cuối. Có vẻ như bảng tra cứu nhanh hơn Math.Sin.
Tôi đoán rằng phương pháp tra cứu sẽ nhanh hơn Math.Sin. Tôi cũng sẽ nói rằng nó sẽ là nhiều hơn nhanh hơn, nhưng câu trả lời của Robert khiến tôi nghĩ rằng tôi vẫn muốn điểm chuẩn này để chắc chắn. Tôi làm rất nhiều xử lý đệm âm thanh, và tôi đã nhận thấy rằng một phương pháp như thế này:
for (int i = 0; i < audiodata.Length; i++)
{
audiodata[i] *= 0.5;
}
sẽ thực hiện nhanh hơn đáng kể so với
for (int i = 0; i < audiodata.Length; i++)
{
audiodata[i] = Math.Sin(audiodata[i]);
}
Nếu sự khác biệt giữa Math.sin và một phép nhân đơn giản là đáng kể, tôi đoán rằng sự khác biệt giữa Math.Sin và tra cứu cũng sẽ là đáng kể.
Tôi không biết, và máy tính của tôi với Visual Studio nằm trong tầng hầm và tôi quá mệt mỏi để dành 2 phút để xác định điều này.
Cập nhật: OK, phải mất hơn 2 phút (hơn như 20) để kiểm tra điều này, nhưng có vẻ như Math.sin là ít nhất hai lần nhanh như một bảng tra cứu (sử dụng một từ điển). Đây là lớp Sin dùng Math.Sin hoặc một bảng tra cứu:
public class SinBuddy
{
private Dictionary<double, double> _cachedSins
= new Dictionary<double, double>();
private const double _cacheStep = 0.01;
private double _factor = Math.PI/180.0;
public SinBuddy()
{
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += _cacheStep)
{
double angleRadians = angleDegrees * _factor;
_cachedSins.Add(angleDegrees, Math.Sin(angleRadians));
}
}
public double CacheStep
{
get
{
return _cacheStep;
}
}
public double SinLookup(double angleDegrees)
{
double value;
if (_cachedSins.TryGetValue(angleDegrees, out value))
{
return value;
}
else
{
throw new ArgumentException(
String.Format("No cached Sin value for {0} degrees",
angleDegrees));
}
}
public double Sin(double angleDegrees)
{
double angleRadians = angleDegrees * _factor;
return Math.Sin(angleRadians);
}
}
Và đây là các mã kiểm tra/thời gian:
SinBuddy buddy = new SinBuddy();
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
int loops = 200;
// Math.Sin
timer.Start();
for (int i = 0; i < loops; i++)
{
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += buddy.CacheStep)
{
double d = buddy.Sin(angleDegrees);
}
}
timer.Stop();
MessageBox.Show(timer.ElapsedMilliseconds.ToString());
// lookup
timer.Start();
for (int i = 0; i < loops; i++)
{
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += buddy.CacheStep)
{
double d = buddy.SinLookup(angleDegrees);
}
}
timer.Stop();
MessageBox.Show(timer.ElapsedMilliseconds.ToString());
Sử dụng một giá trị bước 0,01 độ và Looping qua đầy đủ các giá trị gấp 200 lần (như trong mã này) mất khoảng 1,4 giây sử dụng Math.Sin và khoảng 3,2 giây bằng cách sử dụng bảng tra cứu từ điển. Việc giảm giá trị bước xuống 0,001 hoặc 0,0001 khiến cho việc tra cứu hoạt động thậm chí tệ hơn với Math.Sin. Ngoài ra, kết quả này thậm chí còn có lợi hơn cho việc sử dụng Math.Sin, vì SinBuddy.Sin thực hiện phép nhân để biến góc theo độ thành radian trên mọi cuộc gọi, trong khi SinBuddy.SinLookup chỉ thực hiện tra cứu thẳng.
Đây là máy tính xách tay giá rẻ (không có lõi kép hoặc bất kỳ thứ gì lạ mắt). Robert, bạn da man! (Nhưng tôi vẫn nghĩ rằng tôi sẽ nhận được kiểm tra, coz tôi đã làm công việc).
Cập nhật 2: OK, tôi hoàn toàn chậm phát triển. Nó quay ra dừng lại và khởi động lại đồng hồ bấm giờ không thiết lập lại các mili giây trôi qua, do đó, tra cứu chỉ có vẻ một nửa nhanh vì đó là thời gian đã bao gồm thời gian cho các cuộc gọi Math.Sin. Ngoài ra, tôi đọc lại câu hỏi và nhận ra rằng bạn đang nói về việc lưu trữ các giá trị trong một mảng đơn giản, thay vì sử dụng một từ điển. Đây là mã của tôi sửa đổi (tôi rời khỏi mã cũ lên như một lời cảnh báo cho các thế hệ tương lai):
public class SinBuddy
{
private Dictionary<double, double> _cachedSins
= new Dictionary<double, double>();
private const double _cacheStep = 0.01;
private double _factor = Math.PI/180.0;
private double[] _arrayedSins;
public SinBuddy()
{
// set up dictionary
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += _cacheStep)
{
double angleRadians = angleDegrees * _factor;
_cachedSins.Add(angleDegrees, Math.Sin(angleRadians));
}
// set up array
int elements = (int)(360.0/_cacheStep) + 1;
_arrayedSins = new double[elements];
int i = 0;
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += _cacheStep)
{
double angleRadians = angleDegrees * _factor;
//_cachedSins.Add(angleDegrees, Math.Sin(angleRadians));
_arrayedSins[i] = Math.Sin(angleRadians);
i++;
}
}
public double CacheStep
{
get
{
return _cacheStep;
}
}
public double SinArrayed(double angleDegrees)
{
int index = (int)(angleDegrees/_cacheStep);
return _arrayedSins[index];
}
public double SinLookup(double angleDegrees)
{
double value;
if (_cachedSins.TryGetValue(angleDegrees, out value))
{
return value;
}
else
{
throw new ArgumentException(
String.Format("No cached Sin value for {0} degrees",
angleDegrees));
}
}
public double Sin(double angleDegrees)
{
double angleRadians = angleDegrees * _factor;
return Math.Sin(angleRadians);
}
}
Và mã kiểm tra/thời gian:
SinBuddy buddy = new SinBuddy();
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
int loops = 200;
// Math.Sin
timer.Start();
for (int i = 0; i < loops; i++)
{
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += buddy.CacheStep)
{
double d = buddy.Sin(angleDegrees);
}
}
timer.Stop();
MessageBox.Show(timer.ElapsedMilliseconds.ToString());
// lookup
timer = new System.Diagnostics.Stopwatch();
timer.Start();
for (int i = 0; i < loops; i++)
{
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += buddy.CacheStep)
{
double d = buddy.SinLookup(angleDegrees);
}
}
timer.Stop();
MessageBox.Show(timer.ElapsedMilliseconds.ToString());
// arrayed
timer = new System.Diagnostics.Stopwatch();
timer.Start();
for (int i = 0; i < loops; i++)
{
for (double angleDegrees = 0; angleDegrees <= 360.0;
angleDegrees += buddy.CacheStep)
{
double d = buddy.SinArrayed(angleDegrees);
}
}
timer.Stop();
MessageBox.Show(timer.ElapsedMilliseconds.ToString());
Những kết quả khá khác nhau. Sử dụng Math.Sin mất khoảng 850 mili giây, bảng tra cứu từ điển mất khoảng 1300 mili giây và bảng tra cứu dựa trên mảng mất khoảng 600 mili giây. Vì vậy, có vẻ như một bảng tra cứu (viết đúng) [gulp]) thực sự nhanh hơn một chút so với sử dụng Math.Sin, nhưng không nhiều.
Hãy tự mình xác minh những kết quả này, vì tôi đã chứng tỏ sự thiếu năng lực của mình.
Để tính toán 360000 giá trị xoang khác nhau ở đây mất khoảng 35 mili giây ... trên một sợi đơn. (AMD Quadcore 3 Ghz.) Bạn có tính toán nhiều đến mức đây là vấn đề thực hiện không? Bạn có thể truyền bá công việc qua nhiều luồng (và lõi CPU) không? –
ứng dụng là toán học không tầm thường ... chúng ta cần triển khai các tín hiệu phổ của tín hiệu quang phổ - ví dụ: hưởng từ hạt nhân. có thể có 10^5-10^8 phép đo ... có vẻ như lãng phí để tính toán lại cùng một giá trị nhiều lần ... – mson
Có một câu hỏi tương tự ở đây với một số lựa chọn khác: http://stackoverflow.com/questions/1164492/sine-table-interpolation – Nosredna