/fp
(Tentukan perilaku titik mengambang)
Menentukan bagaimana pengkompilasi memperlakukan ekspresi floating-point, pengoptimalan, dan pengecualian. Opsi /fp
menentukan apakah kode yang dihasilkan memungkinkan perubahan lingkungan floating-point ke mode pembulatan, masker pengecualian, dan perilaku subnormal, dan apakah pemeriksaan status floating-point mengembalikan hasil yang saat ini dan akurat. Ini mengontrol apakah kompilator menghasilkan kode yang mempertahankan operasi sumber dan urutan ekspresi, dan sesuai dengan standar untuk penyebaran NaN. Atau, jika sebaliknya menghasilkan kode yang lebih efisien yang dapat menyusun ulang atau menggabungkan operasi dan menggunakan penyederhanaan transformasi aljabar yang tidak diizinkan oleh standar IEEE-754.
Sintaks
/fp:contract
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
Argumen
/fp:contract
Opsi ini /fp:contract
memungkinkan pengkompilasi untuk menghasilkan kontraksi floating-point saat Anda menentukan /fp:precise
opsi dan /fp:except
. Kontraksi adalah instruksi mesin yang menggabungkan operasi floating-point, seperti Fused-Multiply-Add (FMA). FMA, yang didefinisikan sebagai operasi dasar oleh IEEE-754, tidak membulatkan produk perantara sebelum penambahan, sehingga hasilnya dapat berbeda dari operasi perkalian dan penambahan terpisah. Karena diimplementasikan sebagai satu instruksi, itu bisa lebih cepat daripada instruksi terpisah. Kecepatan datang dengan biaya hasil bitwise yang tepat, dan ketidakmampuan untuk memeriksa nilai perantara.
Secara default, /fp:fast
opsi mengaktifkan /fp:contract
. Opsi /fp:contract
tidak kompatibel dengan /fp:strict
.
Opsi /fp:contract
ini baru di Visual Studio 2022.
/fp:precise
Secara default, pengkompilasi menggunakan /fp:precise
perilaku.
Di bawah /fp:precise
, kompilator mempertahankan properti pengurutan ekspresi sumber dan pembulatan kode floating-point saat menghasilkan dan mengoptimalkan kode objek untuk komputer target. Kompiler membulatkan ke presisi kode sumber pada empat titik tertentu selama evaluasi ekspresi: pada penugasan, typecast, ketika argumen floating-point diteruskan ke panggilan fungsi, dan ketika panggilan fungsi mengembalikan nilai floating-point. Komputasi menengah dapat dilakukan pada presisi mesin. Typecast dapat digunakan untuk secara eksplisit membulatkan komputasi perantara.
Kompilator tidak melakukan transformasi aljabar pada ekspresi floating-point, seperti reassosiasi atau distribusi, kecuali dapat menjamin transformasi menghasilkan hasil yang identik bitwise. Ekspresi yang melibatkan nilai khusus (NaN, +infinity, -infinity, -0.0) diproses sesuai dengan spesifikasi IEEE-754. Misalnya, x != x
mengevaluasi ke true
jika x
adalah NaN. Kontraksi floating-point tidak dihasilkan secara default di bawah /fp:precise
. Perilaku ini baru di Visual Studio 2022. Versi kompilator sebelumnya dapat menghasilkan kontraksi secara default di bawah /fp:precise
.
Kompilator tidak melakukan transformasi aljabar pada ekspresi floating-point, seperti reassosiasi atau distribusi, kecuali dapat menjamin transformasi menghasilkan hasil yang identik bitwise. Ekspresi yang melibatkan nilai khusus (NaN, +infinity, -infinity, -0.0) diproses sesuai dengan spesifikasi IEEE-754. Misalnya, x != x
mengevaluasi ke true
jika x
adalah NaN. Kontraksi floating-point dapat dihasilkan di bawah /fp:precise
.
Pengkompilasi menghasilkan kode yang dimaksudkan untuk dijalankan di lingkungan floating-point default. Ini juga mengasumsikan lingkungan floating-point tidak diakses atau dimodifikasi saat runtime. Artinya, ia mengasumsikan kode: membiarkan pengecualian floating-point ditutupi, tidak membaca atau menulis register status floating-point, dan tidak mengubah mode pembulatan.
Jika kode floating-point Anda tidak bergantung pada urutan operasi dan ekspresi dalam pernyataan floating-point Anda (misalnya, jika Anda tidak peduli apakah a * b + a * c
dihitung sebagai (b + c) * a
atau 2 * a
sebagai a + a
), pertimbangkan /fp:fast
opsi, yang dapat menghasilkan kode yang lebih cepat dan lebih efisien. Jika kode Anda bergantung pada urutan operasi dan ekspresi, dan mengakses atau mengubah lingkungan floating-point (misalnya, untuk mengubah mode pembulatan atau untuk menjebak pengecualian floating-point), gunakan /fp:strict
.
/fp:strict
/fp:strict
memiliki perilaku yang mirip /fp:precise
dengan , yaitu, pengkompilasi mempertahankan properti pengurutan sumber dan pembulatan kode floating-point saat menghasilkan dan mengoptimalkan kode objek untuk komputer target, dan mengamati standar saat menangani nilai khusus. Program ini juga dapat mengakses atau memodifikasi lingkungan floating-point dengan aman saat runtime.
Di bawah /fp:strict
, pengkompilasi menghasilkan kode yang memungkinkan program untuk membuka kemasan pengecualian floating-point dengan aman, membaca atau menulis daftar status floating-point, atau mengubah mode pembulatan. Ini membulatkan ke presisi kode sumber pada empat titik tertentu selama evaluasi ekspresi: pada penugasan, typecast, ketika argumen floating-point diteruskan ke panggilan fungsi, dan ketika panggilan fungsi mengembalikan nilai floating-point. Komputasi menengah dapat dilakukan pada presisi mesin. Typecast dapat digunakan untuk secara eksplisit membulatkan komputasi perantara. Kompilator tidak membuat transformasi aljabar pada ekspresi floating-point, seperti reassosiasi atau distribusi, kecuali dapat menjamin transformasi menghasilkan hasil yang identik bitwise. Ekspresi yang melibatkan nilai khusus (NaN, +infinity, -infinity, -0.0) diproses sesuai dengan spesifikasi IEEE-754. Misalnya, x != x
mengevaluasi ke true
jika x
adalah NaN. Kontraksi floating-point tidak dihasilkan di bawah /fp:strict
.
/fp:strict
secara komputasi lebih mahal daripada /fp:precise
karena kompilator harus memasukkan instruksi tambahan untuk menjebak pengecualian dan memungkinkan program untuk mengakses atau memodifikasi lingkungan floating-point saat runtime. Jika kode Anda tidak menggunakan kemampuan ini, tetapi memerlukan pengurutan dan pembulatan kode sumber, atau bergantung pada nilai khusus, gunakan /fp:precise
. Jika tidak, pertimbangkan untuk menggunakan /fp:fast
, yang dapat menghasilkan kode yang lebih cepat dan lebih kecil.
/fp:fast
Opsi ini /fp:fast
memungkinkan pengompilasi untuk menyusun ulang, menggabungkan, atau menyederhanakan operasi floating-point untuk mengoptimalkan kode floating-point untuk kecepatan dan ruang. Pengkompilasi dapat menghilangkan pembulatan pada pernyataan penugasan, typecast, atau panggilan fungsi. Ini dapat menyusun ulang operasi atau membuat transformasi aljabar, misalnya, dengan menggunakan undang-undang asosiatif dan distributif. Ini dapat menyusun ulang kode bahkan jika transformasi tersebut mengakibatkan perilaku pembulatan yang dapat diamati berbeda. Karena pengoptimalan yang ditingkatkan ini, hasil dari beberapa komputasi floating-point mungkin berbeda dari yang dihasilkan oleh opsi lain /fp
. Nilai khusus (NaN, +infinity, -infinity, -0.0) mungkin tidak disebarluaskan atau berperilaku ketat sesuai dengan standar IEEE-754. Kontraksi floating-point dapat dihasilkan di bawah /fp:fast
. Pengkompilasi masih terikat oleh arsitektur yang mendasar di bawah /fp:fast
, dan lebih banyak pengoptimalan mungkin tersedia melalui penggunaan /arch
opsi .
Di bawah /fp:fast
, kompilator menghasilkan kode yang dimaksudkan untuk dijalankan di lingkungan floating-point default dan mengasumsikan lingkungan floating-point tidak diakses atau dimodifikasi saat runtime. Artinya, ia mengasumsikan kode: membiarkan pengecualian floating-point ditutupi, tidak membaca atau menulis register status floating-point, dan tidak mengubah mode pembulatan.
/fp:fast
ditujukan untuk program yang tidak memerlukan pengurutan kode sumber yang ketat dan pembulatan ekspresi floating-point, dan tidak bergantung pada aturan standar untuk menangani nilai khusus seperti NaN
. Jika kode floating-point Anda memerlukan pelestarian pengurutan dan pembulatan kode sumber, atau bergantung pada perilaku standar nilai khusus, gunakan /fp:precise
. Jika kode Anda mengakses atau memodifikasi lingkungan floating-point untuk mengubah mode pembulatan, membuka kemas pengecualian floating-point, atau memeriksa status floating-point, gunakan /fp:strict
.
/fp:except
Opsi ini /fp:except
menghasilkan kode untuk memastikan bahwa setiap pengecualian floating-point yang tidak dimasak dinaikkan pada titik yang tepat di mana mereka terjadi, dan bahwa tidak ada pengecualian floating-point lainnya yang dimunculkan. Secara default, /fp:strict
opsi mengaktifkan /fp:except
, dan /fp:precise
tidak. Opsi /fp:except
tidak kompatibel dengan /fp:fast
. Opsi dapat dinonaktifkan secara eksplisit dengan menggunakan /fp:except-
.
Dengan sendirinya, /fp:except
tidak mengaktifkan pengecualian floating-point apa pun. Namun, diperlukan program untuk mengaktifkan pengecualian floating-point. Untuk informasi selengkapnya tentang cara mengaktifkan pengecualian floating-point, lihat _controlfp
.
Keterangan
Beberapa /fp
opsi dapat ditentukan dalam baris perintah pengkompilasi yang sama. Hanya salah /fp:strict
satu opsi , /fp:fast
, dan /fp:precise
yang dapat berlaku pada satu waktu. Jika Anda menentukan lebih dari salah satu opsi ini pada baris perintah, opsi selanjutnya lebih diutamakan dan pengkompilasi menghasilkan peringatan. Opsi /fp:strict
dan /fp:except
tidak kompatibel dengan /clr
.
Opsi /Za
(kompatibilitas ANSI) tidak kompatibel dengan /fp
.
Menggunakan direktif kompilator untuk mengontrol perilaku floating-point
Kompilator menyediakan tiga arahan pragma untuk mengambil alih perilaku floating-point yang ditentukan pada baris perintah: float_control
, , fenv_access
dan fp_contract
. Anda dapat menggunakan arahan ini untuk mengontrol perilaku floating-point pada tingkat fungsi, bukan dalam fungsi. Arahan ini tidak sesuai langsung /fp
dengan opsi. Tabel ini menunjukkan bagaimana /fp
opsi dan arahan pragma memetakan satu sama lain. Untuk informasi selengkapnya, lihat dokumentasi untuk masing-masing opsi dan arahan pragma.
Opsi | float_control(precise, *) |
float_control(except, *) |
fenv_access(*) |
fp_contract(*) |
---|---|---|---|---|
/fp:fast |
off |
off |
off |
on |
/fp:precise |
on |
off |
off |
off * |
/fp:strict |
on |
on |
on |
off |
* Dalam versi Visual Studio sebelum Visual Studio 2022, /fp:precise
perilaku default ke fp_contract(on)
.
Opsi | float_control(precise, *) |
float_control(except, *) |
fenv_access(*) |
fp_contract(*) |
---|---|---|---|---|
/fp:fast |
off |
off |
off |
on |
/fp:precise |
on |
off |
off |
on * |
/fp:strict |
on |
on |
on |
off |
* Dalam versi Visual Studio yang dimulai dengan Visual Studio 2022, /fp:precise
perilaku default ke fp_contract(off)
.
Lingkungan titik mengambang default
Saat proses diinisialisasi, lingkungan floating point default diatur. Lingkungan ini menutupi semua pengecualian titik mengambang, mengatur mode pembulatan ke bulat ke terdekat (FE_TONEAREST
), mempertahankan nilai subnormal (denormal), menggunakan presisi default significand (mantissa) untuk float
, , double
dan long double
nilai, dan jika didukung, mengatur kontrol tak terbatas ke mode affine default.
Akses dan modifikasi lingkungan floating-point
Runtime Microsoft Visual C++ menyediakan beberapa fungsi untuk mengakses dan memodifikasi lingkungan floating-point. Ini termasuk _controlfp
, _clearfp
, dan _statusfp
variannya. Untuk memastikan perilaku program yang benar ketika kode Anda mengakses atau memodifikasi lingkungan floating-point, fenv_access
harus diaktifkan, baik dengan /fp:strict
opsi atau dengan menggunakan fenv_access
pragma, agar fungsi-fungsi ini memiliki efek apa pun. Ketika fenv_access
tidak diaktifkan, akses atau modifikasi lingkungan floating-point dapat mengakibatkan perilaku program yang tidak terduga:
Kode mungkin tidak mematuhi perubahan yang diminta pada lingkungan floating-point,
Register status floating-point mungkin tidak melaporkan hasil yang diharapkan atau saat ini,
Pengecualian floating-point yang tidak terduga mungkin terjadi atau pengecualian floating-point yang diharapkan mungkin tidak terjadi.
Saat kode Anda mengakses atau memodifikasi lingkungan floating-point, Anda harus berhati-hati saat menggabungkan kode di mana fenv_access
diaktifkan dengan kode yang belum fenv_access
diaktifkan. Dalam kode di mana fenv_access
tidak diaktifkan, pengkompilasi mengasumsikan lingkungan floating-point default platform berlaku. Ini juga mengasumsikan status floating-point tidak diakses atau dimodifikasi. Sebaiknya simpan dan pulihkan lingkungan floating-point lokal ke status defaultnya sebelum kontrol ditransfer ke fungsi yang belum fenv_access
diaktifkan. Contoh ini menunjukkan bagaimana float_control
pragma dapat diatur dan dipulihkan:
#pragma float_control(precise, on, push)
// Code that uses /fp:strict mode
#pragma float_control(pop)
Mode pembulatan titik mengambang
/fp:precise
Di bawah dan /fp:fast
, pengkompilasi menghasilkan kode yang dimaksudkan untuk dijalankan di lingkungan floating-point default. Ini mengasumsikan bahwa lingkungan tidak diakses atau dimodifikasi saat runtime. Artinya, kompilator mengasumsikan kode tidak pernah membuka kemasan pengecualian floating-point, membaca atau menulis daftar status floating-point, atau mengubah mode pembulatan. Namun, beberapa program perlu mengubah lingkungan floating-point. Misalnya, sampel ini menghitung batas kesalahan dari perkalian floating-point dengan mengubah mode pembulatan floating-point:
// fp_error_bounds.cpp
#include <iostream>
#include <limits>
using namespace std;
int main(void)
{
float a = std::<float>::max();
float b = -1.1;
float cLower = 0.0;
float cUpper = 0.0;
unsigned int control_word = 0;
int err = 0;
// compute lower error bound.
// set rounding mode to -infinity.
err = _controlfp_s(&control_word, _RC_DOWN, _MCW_RC);
if (err)
{
cout << "_controlfp_s(&control_word, _RC_DOWN, _MCW_RC) failed with error:" << err << endl;
}
cLower = a * b;
// compute upper error bound.
// set rounding mode to +infinity.
err = _controlfp_s(&control_word, _RC_UP, _MCW_RC);
if (err)
{
cout << "_controlfp_s(&control_word, _RC_UP, _MCW_RC) failed with error:" << err << endl;
}
cUpper = a * b;
// restore default rounding mode.
err = _controlfp_s(&control_word, _CW_DEFAULT, _MCW_RC);
if (err)
{
cout << "_controlfp_s(&control_word, _CW_DEFAULT, _MCW_RC) failed with error:" << err << endl;
}
// display error bounds.
cout << "cLower = " << cLower << endl;
cout << "cUpper = " << cUpper << endl;
return 0;
}
Karena kompilator mengasumsikan lingkungan floating point default di bawah /fp:fast
dan /fp:precise
, bebas untuk mengabaikan panggilan ke _controlfp_s
. Misalnya, saat dikompilasi dengan menggunakan dan /O2
/fp:precise
untuk arsitektur x86, batasan tidak dihitung, dan output program sampel:
cLower = -inf
cUpper = -inf
Saat dikompilasi dengan menggunakan dan /O2
/fp:strict
untuk arsitektur x86, contoh output program:
cLower = -inf
cUpper = -3.40282e+38
Nilai khusus floating-point
Di bawah /fp:precise
dan /fp:strict
, ekspresi yang melibatkan nilai khusus (NaN, +infinity, -infinity, -0.0) berperilaku sesuai dengan spesifikasi IEEE-754. Di bawah /fp:fast
, perilaku nilai khusus ini mungkin tidak konsisten dengan IEEE-754.
Sampel ini menunjukkan perilaku yang berbeda dari nilai khusus di bawah /fp:precise
, , /fp:strict
dan /fp:fast
:
// fp_special_values.cpp
#include <stdio.h>
#include <cmath>
float gf0 = -0.0;
int main()
{
float f1 = INFINITY;
float f2 = NAN;
float f3 = -INFINITY;
bool a, b;
float c, d, e;
a = (f1 == f1);
b = (f2 == f2);
c = (f1 - f1);
d = (f2 - f2);
e = (gf0 / f3);
printf("INFINITY == INFINITY : %d\n", a);
printf("NAN == NAN : %d\n", b);
printf("INFINITY - INFINITY : %f\n", c);
printf("NAN - NAN : %f\n", d);
printf("std::signbit(-0.0/-INFINITY): %d\n", std::signbit(e));
return 0;
}
Saat dikompilasi dengan menggunakan /O2 /fp:precise
atau /O2 /fp:strict
untuk arsitektur x86, output konsisten dengan spesifikasi IEEE-754:
INFINITY == INFINITY : 1
NAN == NAN : 0
INFINITY - INFINITY : -nan(ind)
NAN - NAN : nan
std::signbit(-0.0/-INFINITY): 0
Saat dikompilasi dengan menggunakan /O2 /fp:fast
** untuk arsitektur x86, output tidak konsisten dengan IEEE-754:
INFINITY == INFINITY : 1
NAN == NAN : 1
INFINITY - INFINITY : 0.000000
NAN - NAN : 0.000000
std::signbit(-0.0/-INFINITY): 0
Transformasi aljabar titik mengambang
Di bawah /fp:precise
dan /fp:strict
, pengkompilasi tidak melakukan transformasi matematika kecuali transformasi dijamin menghasilkan hasil yang identik bitwise. Pengkompilasi dapat membuat transformasi seperti itu di bawah /fp:fast
. Misalnya, ekspresi a * b + a * c
dalam fungsi algebraic_transformation
sampel dapat dikompilasi ke dalam a * (b + c)
./fp:fast
Transformasi tersebut tidak dilakukan di bawah /fp:precise
atau /fp:strict
, dan pengkompilasi menghasilkan a * b + a * c
.
float algebraic_transformation (float a, float b, float c)
{
return a * b + a * c;
}
Titik pengecoran eksplisit floating-point
Di bawah /fp:precise
dan /fp:strict
, pengkompilasi membulatkan ke presisi kode sumber pada empat titik tertentu selama evaluasi ekspresi: pada penugasan, typecast, ketika argumen floating-point diteruskan ke panggilan fungsi, dan ketika panggilan fungsi mengembalikan nilai floating-point. Typecast dapat digunakan untuk secara eksplisit membulatkan komputasi perantara. Di bawah /fp:fast
, pengkompilasi tidak menghasilkan cast eksplisit pada titik-titik ini untuk menjamin presisi kode sumber. Sampel ini menunjukkan perilaku di bawah opsi yang berbeda /fp
:
float casting(float a, float b)
{
return 5.0*((double)(a+b));
}
Saat dikompilasi dengan menggunakan /O2 /fp:precise
atau /O2 /fp:strict
, Anda dapat melihat bahwa jenis cast eksplisit disisipkan di typecast dan pada titik pengembalian fungsi dalam kode yang dihasilkan untuk arsitektur x64:
addss xmm0, xmm1
cvtss2sd xmm0, xmm0
mulsd xmm0, QWORD PTR __real@4014000000000000
cvtsd2ss xmm0, xmm0
ret 0
Di bawah /O2 /fp:fast
kode yang dihasilkan disederhanakan, karena semua jenis cast dioptimalkan:
addss xmm0, xmm1
mulss xmm0, DWORD PTR __real@40a00000
ret 0
Untuk mengatur opsi pengkompilasi ini di lingkungan pengembangan Visual Studio
Buka kotak dialog Halaman Properti proyek. Untuk detailnya, lihat Mengatur pengkompilasi C++ dan membuat properti di Visual Studio.
Pilih halaman properti Properti>Konfigurasi C/C++>Code Generation.
Ubah properti Model Titik Mengambang.
Untuk mengatur opsi pengkompilasi ini secara terprogram
- Lihat floatingPointModel.
Baca juga
Opsi pengkompilasi MSVC
Sintaks baris perintah pengkompilasi MSVC
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk