MIN dan MAX dalam C

301

Di mana MINdan MAXdidefinisikan dalam C, jika ada?

Apa cara terbaik untuk menerapkan ini, secara umum dan ketik seaman mungkin? (Ekstensi kompiler / builtin untuk kompiler arus utama lebih disukai.)

Matt Joiner
sumber

Jawaban:

392

Di mana MINdan MAXdidefinisikan dalam C, jika ada?

Mereka bukan.

Apa cara terbaik untuk mengimplementasikannya, secara umum dan ketik seaman mungkin (ekstensi kompiler / builtin untuk kompiler arus utama lebih disukai).

Sebagai fungsi. Saya tidak akan menggunakan makro seperti #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), terutama jika Anda berencana untuk menyebarkan kode Anda. Entah menulis sendiri, gunakan sesuatu seperti standar fmaxatau fmin, atau perbaiki makro menggunakan GCC typeof (Anda juga mendapatkan bonus typesafety) dalam ekspresi pernyataan GCC :

 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

Semua orang mengatakan "oh saya tahu tentang evaluasi ganda, tidak ada masalah" dan beberapa bulan kemudian, Anda akan men-debug masalah paling konyol selama berjam-jam.

Perhatikan penggunaan __typeof__bukannya typeof:

Jika Anda menulis file header yang harus berfungsi saat disertakan dalam program ISO C, tulislah __typeof__alih-alih typeof.

David Titarenco
sumber
68
Anda tahu, akan sangat berguna jika gcc memiliki peringatan di sepanjang baris: warning: expression with side-effects multiply evaluated by macropada titik penggunaan ...
caf
23
@caf: bukankah itu mensyaratkan bahwa preprocessor memiliki pengetahuan yang lebih rumit tentang sintaks C?
dreamlax
3
Setelah banyak berusaha mencari tahu, saya tidak berpikir ada cara lain untuk melakukan ini di VC ++, tetapi yang terbaik adalah mencoba mengacaukan decltypekata kunci baru MSVC ++ 2010 - tetapi meskipun demikian, Visual Studio tidak dapat melakukan pernyataan majemuk dalam makro (dan decltypeC ++ pula), yaitu ({ ... })sintaks GCC jadi saya cukup yakin itu tidak mungkin. Saya belum melihat kompiler lain mengenai masalah ini, maaf Luther: S
David Titarenco
7
@dreamlax Saya pernah melihat kasus di mana seseorang telah melakukan MAX(someUpperBound, someRandomFunction())untuk membatasi nilai acak ke batas atas. Itu adalah ide yang mengerikan, tetapi bahkan tidak berhasil, karena yang MAXdia gunakan memiliki masalah evaluasi ganda, jadi dia berakhir dengan angka acak yang berbeda dari yang awalnya dievaluasi.
Zev Eisenberg
8
@Sumumen Misalnya, jika Anda memanggil MIN(x++, y++)preprocessor akan menghasilkan kode berikut (((x++) < (y++)) ? (x++) : (y++)). Jadi, xdan yakan bertambah dua kali.
Antonio
91

Ini juga disediakan dalam versi GNU libc (Linux) dan FreeBSD dari sys / param.h, dan memiliki definisi yang disediakan oleh dreamlax.


Di Debian:

$ uname -sr
Linux 2.6.11

$ cat /etc/debian_version
5.0.2

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

$ head -n 2 /usr/include/sys/param.h | grep GNU
This file is part of the GNU C Library.

Di FreeBSD:

$ uname -sr
FreeBSD 5.5-STABLE

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

Repositori sumber ada di sini:

Mikel
sumber
Saya telah menambahkan definisi dari sistem yang dapat saya akses dalam jawaban saya di atas (kolom komentar tidak menerima pemformatan sejauh yang saya tahu). Akan mencoba menemukan tautan ke repo sumber FreeBSD / Linux / glibc.
Mikel
+1. Sangat bagus. Bekerja untuk openSUSE/Linux 3.1.0-1.2-desktop/ gcc version 4.6.2 (SUSE Linux) juga. :) Buruk itu tidak portabel.
Jack
Bekerja pada Cygwin juga.
CMCDragonkai
1
Tunggu sebentar. Itu tidak mencegah evaluasi ganda, bukan? : 3
user1857492
76

Ada a std::mindan std::maxdi C ++, tapi AFAIK, tidak ada yang setara di pustaka standar C. Anda dapat mendefinisikannya sendiri dengan makro seperti

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

Tetapi ini menyebabkan masalah jika Anda menulis sesuatu seperti MAX(++a, ++b).

dan04
sumber
10
mengapa menaruh terlalu banyak tanda kurung ??? Saya menemukan kuis di mana mereka mengatakan #define MIN(A, B) ((A < B) ? A : B)itu bukan cara yang fleksibel, mengapa ???
79
@Makouda: Kurung tambahan dalam makro membantu menghindari masalah prioritas operator. Sebagai contoh, pertimbangkan #define MULT(x, y) x * y. Kemudian MULT(a + b, a + b)mengembang ke a + b * a + b, yang mem-parsing a + (b * a) + bkarena didahulukan. Bukan itu yang dimaksudkan oleh programmer.
dan04
yang tidak diperlukan kapan
?:
1
@WingerSendon: Tidak; operator koma tidak.
dan04
24

Hindari ekstensi kompiler non-standar dan implementasikan sebagai makro yang benar-benar aman di C standar murni (ISO 9899: 2011).

Larutan

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

Pemakaian

MAX(int, 2, 3)

Penjelasan

Max makro menciptakan makro lain berdasarkan typeparameter. Makro kontrol ini, jika diimplementasikan untuk jenis yang diberikan, digunakan untuk memeriksa bahwa kedua parameter dari jenis yang benar. Jika typetidak didukung, akan ada kesalahan kompiler.

Jika salah satu x atau y bukan dari jenis yang benar, akan ada kesalahan kompilator di ENSURE_makro. Lebih banyak makro seperti itu dapat ditambahkan jika lebih banyak jenis yang didukung. Saya berasumsi bahwa hanya tipe aritmatika (integer, float, pointer dll) yang akan digunakan dan bukan struct atau array dll.

Jika semua jenis sudah benar, makro GENERIC_MAX akan dipanggil. Tanda kurung tambahan diperlukan di sekitar setiap parameter makro, sebagai tindakan pencegahan standar yang biasa saat menulis makro C.

Lalu ada masalah biasa dengan promosi tipe implisit di C. ?:Operator menyeimbangkan operan ke-2 dan ke-3 terhadap satu sama lain. Misalnya, hasil dari GENERIC_MAX(my_char1, my_char2)akan menjadi int. Untuk mencegah makro dari melakukan promosi tipe yang berpotensi berbahaya seperti itu, tipe final cast ke tipe yang dimaksud digunakan.

Alasan

Kami ingin kedua parameter makro memiliki tipe yang sama. Jika salah satu dari mereka adalah tipe yang berbeda, makro tidak lagi aman, karena operator seperti ?:akan menghasilkan promosi tipe implisit. Dan karena itu terjadi, kita juga selalu perlu mengembalikan hasil akhir ke jenis yang dimaksud seperti dijelaskan di atas.

Makro dengan hanya satu parameter bisa ditulis dengan cara yang lebih sederhana. Tetapi dengan 2 atau lebih parameter, ada kebutuhan untuk memasukkan parameter tipe tambahan. Karena sesuatu seperti ini sayangnya tidak mungkin:

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

Masalahnya adalah bahwa jika makro di atas disebut MAX(1, 2)dengan dua int, makro masih akan mencoba untuk memperluas semua skenario yang mungkin dari _Genericdaftar asosiasi. Jadi ENSURE_floatmakro juga akan diperluas, meskipun tidak relevan untuk itu int. Dan karena makro itu sengaja hanya berisi floattipe, kode tidak akan dikompilasi.

Untuk mengatasi ini, saya membuat nama makro selama fase pra-prosesor sebagai gantinya, dengan operator ##, sehingga tidak ada makro yang diperluas secara tidak sengaja.

Contohnya

#include <stdio.h>

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

int main (void)
{
  int    ia = 1,    ib = 2;
  float  fa = 3.0f, fb = 4.0f;
  double da = 5.0,  db = 6.0;

  printf("%d\n", MAX(int,   ia, ib)); // ok
  printf("%f\n", MAX(float, fa, fb)); // ok

//printf("%d\n", MAX(int,   ia, fa));  compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib));  compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db));  compiler error, one of the types is wrong

//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
  return 0;
}
Lundin
sumber
Itu GENERIC_MAXmakro adalah ide yang buruk dengan cara, Anda hanya harus mencoba GENERIC_MAX(var++, 7)untuk mencari tahu mengapa :-) Saat ini (terutama dengan berat mengoptimalkan / compiler inlining), makro harus cukup banyak diturunkan ke bentuk yang sederhana saja. Fungsi seperti lebih baik sebagai fungsi dan yang nilai-kelompok lebih baik sebagai enumerasi.
paxdiablo
21

Saya tidak berpikir bahwa itu adalah makro standar. Sudah ada fungsi standar untuk floating point, fmaxdan fmin(dan fmaxfuntuk float, dan fmaxluntuk double panjang).

Anda dapat menerapkannya sebagai makro selama Anda mengetahui masalah efek samping / evaluasi ganda.

#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)

Dalam kebanyakan kasus, Anda dapat menyerahkannya ke kompiler untuk menentukan apa yang Anda coba lakukan dan mengoptimalkannya sebaik mungkin. Sementara ini menyebabkan masalah ketika digunakan seperti MAX(i++, j++), saya ragu ada banyak kebutuhan dalam memeriksa nilai maksimum yang meningkat dalam sekali jalan. Selisih lebih dulu, lalu periksa.

dreamlax
sumber
Ini harus menjadi jawaban yang disukai karena jelas ada fungsi min dan max di perpustakaan matematika: cplusplus.com/reference/cmath/fmax
imranal
@ imranal Apa yang sebenarnya Anda bicarakan? The pelaksanaan kode perpustakaan mereka? Tetapi kode itu tidak diekspos , yaitu mereka tidak menempatkannya di antarmuka perpustakaan, karena berpotensi tidak aman.
Antonio
@Antonio Saya pikir Anda menggunakan definisi yang salah "terbuka" dan "antarmuka". Antarmuka pustaka ac adalah variabel eksternal, tipe, makro, dan deklarasi fungsi dalam file header; fmin / fmax dideklarasikan dalam file header, sehingga dikatakan terbuka. Saya tidak yakin apa yang Anda sebut tidak aman.
rationalcoder
21

Ini adalah jawaban yang terlambat, karena perkembangan yang cukup baru. Karena OP menerima jawaban yang bergantung pada ekstensi GCC (dan dentang) yang tidak portabel typeof- atau __typeof__untuk 'bersih' ISO C - ada solusi yang lebih baik tersedia pada gcc-4.9 .

#define max(x,y) ( \
    { __auto_type __x = (x); __auto_type __y = (y); \
      __x > __y ? __x : __y; })

Manfaat nyata dari ekstensi ini adalah bahwa setiap argumen makro hanya diperluas satu kali, tidak seperti __typeof__solusinya.

__auto_typeadalah bentuk terbatas C ++ 11's auto. Tidak dapat (atau tidak?) Digunakan dalam kode C ++, meskipun tidak ada alasan yang baik untuk tidak menggunakan kemampuan inferensi tipe superior autosaat menggunakan C ++ 11.

Yang mengatakan, saya berasumsi tidak ada masalah menggunakan sintaks ini ketika makro termasuk dalam ruang extern "C" { ... }lingkup; misalnya, dari header C. AFAIK, ekstensi ini belum menemukan info caranya

Brett Hale
sumber
Terkait dengan komentar Brett Hale , clangmulai mendukung __auto_typesekitar 2016 (lihat tambalan ).
Lars
Kudos karena mengenali masalah makro tetapi saya masih berpendapat bahwa suatu fungsi mungkin akan lebih baik :-)
paxdiablo
@ paxdiablo - Saya setuju, meskipun pertanyaan memiliki c-preprocessortag. Suatu fungsi tidak dijamin akan digarisbawahi bahkan dengan kata kunci tersebut, kecuali menggunakan sesuatu seperti __always_inline__atribut gcc .
Brett Hale
11

Saya menulis versi ini yang berfungsi untuk MSVC, GCC, C, dan C ++.

#if defined(__cplusplus) && !defined(__GNUC__)
#   include <algorithm>
#   define MIN std::min
#   define MAX std::max
//#   define TMIN(T, a, b) std::min<T>(a, b)
//#   define TMAX(T, a, b) std::max<T>(a, b)
#else
#       define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \
                ({ \
                        decltype(lexpr) lvar = (lexpr); \
                        decltype(rexpr) rvar = (rexpr); \
                        lvar binoper rvar ? lvar : rvar; \
                })
#       define _CHOOSE_VAR2(prefix, unique) prefix##unique
#       define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique)
#       define _CHOOSE(binoper, lexpr, rexpr) \
                _CHOOSE2( \
                        binoper, \
                        lexpr, _CHOOSE_VAR(_left, __COUNTER__), \
                        rexpr, _CHOOSE_VAR(_right, __COUNTER__) \
                )
#       define MIN(a, b) _CHOOSE(<, a, b)
#       define MAX(a, b) _CHOOSE(>, a, b)
#endif
Matt Joiner
sumber
1
Saya meningkatkan suara tetapi pengidentifikasi dimulai dengan garis bawah diikuti oleh huruf besar dicadangkan.
dreamlax
8

Jika Anda membutuhkan min / maks untuk menghindari cabang yang mahal, Anda sebaiknya tidak menggunakan operator ternary, karena akan dikompilasi menjadi lompatan. Tautan di bawah ini menjelaskan metode yang berguna untuk menerapkan fungsi min / max tanpa bercabang.

http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax

cib
sumber
1
Jika kompiler cukup pintar, ia dapat menghindari cabang
Axel Gneiting
2
Jika optimisasi dihidupkan, semua kompiler modern akan memancarkan langkah bersyarat alih-alih cabang dalam kebanyakan kasus, jadi ada sedikit gunanya menggunakan peretasan seperti ini.
Krzysztof Kosiński
2
Benar sekali, saya tidak tahu apa yang saya lihat saat itu, sudah lama. Baik gcc dan dentang menghindari cabang dengan -O, baik pada x86 dan armv7a.
cib
6

@ David Titarenco memakukannya di sini , tapi biarkan saya setidaknya membersihkannya sedikit agar terlihat bagus, dan tunjukkan keduanya min() dan max() bersama - sama untuk membuat menyalin dan menempel dari sini lebih mudah. :)

Pembaruan 25 April 2020: Saya juga menambahkan Bagian 3 untuk menunjukkan bagaimana hal ini akan dilakukan dengan template C ++, sebagai perbandingan yang berharga bagi mereka yang belajar C dan C ++, atau beralih dari satu ke yang lain. Saya telah melakukan yang terbaik untuk menjadi teliti dan faktual dan benar untuk menjadikan jawaban ini sebagai referensi kanonis yang dapat saya kembalikan lagi dan lagi, dan saya harap Anda merasa ini sama bermanfaatnya dengan saya.

1. Cara makro C lama:

Teknik ini umumnya digunakan, dihormati oleh mereka yang tahu cara menggunakannya dengan benar, cara "de facto" dalam melakukan sesuatu, dan baik untuk digunakan jika digunakan dengan benar, tetapi buggy (pikirkan: efek samping evaluasi ganda ) jika Anda pernah lulus ekspresi termasuk penugasan variabel untuk membandingkan:

#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))

2. Cara " ekspresi pernyataan " gcc yang baru dan lebih baik:

Teknik ini menghindari efek samping dan bug "evaluasi-ganda" di atas, dan karenanya dianggap sebagai cara GCC C yang superior, lebih aman, dan "lebih modern" untuk melakukan ini. Harapkan itu bekerja dengan kompiler gcc dan dentang, karena dentang, secara desain, kompatibel dengan gcc (lihat catatan dentang di bagian bawah jawaban ini).

TETAPI: Tetap berhati-hati terhadap efek " variabel shadowing ", karena ekspresi pernyataan tampaknya digarisbawahi dan karena itu TIDAK memiliki cakupan variabel lokal mereka sendiri!

#define max(a,b)             \
({                           \
    __typeof__ (a) _a = (a); \
    __typeof__ (b) _b = (b); \
    _a > _b ? _a : _b;       \
})

#define min(a,b)             \
({                           \
    __typeof__ (a) _a = (a); \
    __typeof__ (b) _b = (b); \
    _a < _b ? _a : _b;       \
})

Perhatikan bahwa dalam ekspresi pernyataan gcc, ekspresi terakhir dalam blok kode adalah apa yang "dikembalikan" dari ekspresi, seolah-olah itu dikembalikan dari fungsi. Dokumentasi GCC mengatakannya seperti ini:

Hal terakhir dalam pernyataan majemuk adalah ekspresi yang diikuti oleh tanda titik koma; nilai dari subekspresi ini berfungsi sebagai nilai dari keseluruhan konstruk. (Jika Anda menggunakan jenis pernyataan lain yang terakhir di dalam kurung kurawal, konstruk memiliki tipe batal, dan dengan demikian tidak ada nilainya.)

3. Cara templat C ++:

C ++ Catatan: jika menggunakan C ++, templat mungkin direkomendasikan untuk jenis konstruk ini sebagai gantinya, tetapi saya pribadi tidak menyukai templat dan mungkin akan menggunakan salah satu konstruk di atas dalam C ++, karena saya sering menggunakan dan lebih suka gaya C pada embedded C ++ juga.

Bagian ini ditambahkan 25 April 2020:

Saya telah melakukan satu ton C ++ beberapa bulan terakhir, dan tekanan untuk lebih memilih template daripada makro, jika mampu, di komunitas C ++ cukup kuat. Sebagai hasilnya, saya menjadi lebih baik dalam menggunakan templat, dan ingin memasukkan versi templat C ++ di sini untuk kelengkapan dan menjadikannya jawaban yang lebih kanonik dan menyeluruh.

Inilah versi templat fungsi dasar max()dan min()mungkin terlihat seperti di C ++:

template <typename T>
T max(T a, T b)
{
    return a > b ? a : b;
}

template <typename T>
T min(T a, T b)
{
    return a < b ? a : b;
}

Lakukan bacaan tambahan tentang templat C ++ di sini: Wikipedia: Templat (C ++) .

Namun, keduanya max()dan min()sudah menjadi bagian dari pustaka standar C ++, di <algorithm>header ( #include <algorithm>). Di pustaka standar C ++ mereka didefinisikan sedikit berbeda dari yang saya miliki di atas. Prototipe default untuk std::max<>()dan std::min<>(), misalnya, dalam C ++ 14, melihat prototipe mereka di tautan cplusplus.com tepat di atas, adalah:

template <class T> 
constexpr const T& max(const T& a, const T& b);

template <class T> 
constexpr const T& min(const T& a, const T& b);

Perhatikan bahwa kata kunci typenameadalah alias untuk class(sehingga penggunaannya identik apakah Anda katakan <typename T>atau <class T>), karena itu kemudian mengakui setelah penemuan C ++ template, bahwa jenis template mungkin tipe biasa ( int, float, dll) bukan hanya tipe kelas.

Di sini Anda dapat melihat bahwa kedua jenis input, serta jenis kembali, adalah const T&, yang berarti "referensi konstan untuk mengetik T". Ini berarti parameter input dan nilai balik diteruskan dengan referensi alih-alih lewat nilai . Ini seperti melewati pointer, dan lebih efisien untuk tipe besar, seperti objek kelas. Bagian constexprdari fungsi memodifikasi fungsi itu sendiri dan menunjukkan bahwa fungsi tersebut harus mampu dievaluasi pada waktu kompilasi (setidaknya jika diberikan constexprparameter input), tetapi jika tidak dapat dievaluasi pada waktu kompilasi, maka defaultnya kembali ke evaluasi run-time, seperti fungsi normal lainnya.

Aspek waktu kompilasi dari constexprfungsi C ++ membuatnya menjadi semacam makro-C, di mana jika evaluasi waktu kompilasi dimungkinkan untuk suatu constexprfungsi, itu akan dilakukan pada waktu kompilasi, sama seperti substitusi makro MIN()atau MAX()mungkin sepenuhnya dievaluasi pada waktu kompilasi dalam C atau C ++ juga. Untuk referensi tambahan untuk info templat C ++ ini, lihat di bawah.

Referensi:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. MIN dan MAX dalam C
  4. Referensi template C ++ tambahan ditambahkan pada April 2020:
    1. ***** Wikipedia: Templat (C ++) <- Info tambahan BESAR tentang templat C ++!
    2. (Pertanyaan & jawaban saya sendiri): Mengapa `constexpr` bagian dari prototipe template C ++ 14 untuk` std :: max () `?
    3. Perbedaan antara `constexpr` dan` const`

Dentang catatan dari Wikipedia :

[Dentang] dirancang untuk bertindak sebagai pengganti drop-in untuk GNU Compiler Collection (GCC), mendukung sebagian besar bendera kompilasi dan ekstensi bahasa tidak resmi.

Gabriel Staples
sumber
Untuk para downvoter dari 24 jam terakhir: kabar baik! Saya telah menghapus kata-kata kasar Bagian 4 yang saya tambahkan dengan Bagian 3 kemarin, dan saya menaruhnya di sini . Anda dipersilakan mengevaluasi kembali jawaban saya dan memberikannya suara positif jika Anda mau, karena saya telah memasukkan banyak informasi yang baik ke dalamnya dan telah melakukan yang terbaik untuk menjadikannya jawaban yang solid, membantu, kanonik untuk memberi manfaat bagi semua. Sekarang kembali ke fokus. :) terima kasih!
Gabriel Staples
4

Ada baiknya menunjukkan saya pikir jika Anda mendefinisikan mindan maxdengan tersier seperti

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

kemudian untuk mendapatkan hasil yang sama untuk kasus khusus fmin(-0.0,0.0)dan fmax(-0.0,0.0)Anda perlu menukar argumen

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)
Z boson
sumber
Masih tidak akan bekerja untuk NaN. fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
greggo
@ Greggo, saya memberikan jawaban yang lebih baik di sini stackoverflow.com/a/30915238/2542702
Z boson
4

Sepertinya makro Windef.h(a la #include <windows.h>) memiliki maxdan min(huruf kecil), yang juga mengalami kesulitan "evaluasi ganda", tetapi mereka ada di sana untuk mereka yang tidak ingin memutar ulang sendiri :)

rogerdpack
sumber
12
Apakah Anda bahkan terkejut?
Matt Joiner
2

Saya tahu orang itu berkata "C" ... Tetapi jika Anda memiliki kesempatan, gunakan templat C ++:

template<class T> T min(T a, T b) { return a < b ? a : b; }

Ketik aman, dan tidak ada masalah dengan ++ yang disebutkan dalam komentar lain.

Bas Kuenen
sumber
16
Argumen harus menjadi referensi const, Anda tidak pernah tahu pengguna apa yang akan lulus.
nmikhailov
6
Fungsi semacam itu telah distandarisasi ( std :: min ).
dreamlax
C ++ memiliki banyak fungsi standar untuk sebagian besar tujuan normal, jangan menemukan kembali roda. Namun MS juga mendefinisikan min / max mereka sendiri yang terkadang menyebabkan masalah
phuclv
0

Maksimal dua bilangan bulat adan badalah (int)(0.5((a+b)+abs(a-b))). Ini juga dapat bekerja dengan (double)dan fabs(a-b)untuk ganda (serupa untuk pelampung)

NRZ
sumber
Maaf jika ini salah, saya seorang pemula C tetapi kode ini berfungsi untuk saya
NRZ
2
Saya tidak yakin ini berfungsi dengan non integer. Matematika floating point memiliki presisi nonlinear.
Treesrule14
Untuk memperluas komentar @ Treesrule14: Ini tidak berfungsi karena komputer tidak memperlakukan angka dengan cara yang sama seperti ahli matematika. Floating point memiliki masalah pembulatan, jadi Anda tidak mungkin mendapatkan jawaban yang tepat. Bahkan jika Anda menggunakan bilangan bulat matematika, MAX_INT + MAX_INT memberi -2, jadi max (MAX_INT, MAX_INT) menggunakan rumus Anda akan keluar sebagai -1.
user9876
-3

Cara paling sederhana adalah mendefinisikannya sebagai fungsi global dalam suatu .hfile, dan menyebutnya kapan saja Anda inginkan, jika program Anda bersifat modular dengan banyak file. Jika tidak, double MIN(a,b){return (a<b?a:b)}adalah cara paling sederhana.

srezat
sumber
1
@ technosaurus Akan sangat membantu jika Anda menjelaskan mengapa solusi ini salah, tidak hanya itu.
Tur1ng
@ technosaurus, respons Anda benar-benar tidak membantu. Tur1ing, tampak bahwa fungsi didefinisikan sepenuhnya salah (jenis yang hilang pada params input, hilang titik koma setelah pernyataan kembali), dan mengubah input int menjadi ganda adalah cara yang buruk untuk melakukan sesuatu, jadi jenisnya tidak boleh ganda. Ekspresi define atau statement akan lebih baik di sini (mis: lihat di sini ), tetapi jika suatu fungsi, pertimbangkan membuat satu fungsi untuk melakukan ini untuk tipe int32_t, satu untuk tipe uint32_t, dan satu untuk tipe float atau double, dengan total 3 fungsi yang berbeda.
Gabriel Staples
1
@GabrielStaples Jawaban ini harus ditandai sebagai bukan jawaban - tidak ada yang membantunya. Meskipun bisa digunakan sebagai contoh bagaimana menjadi yang paling salah dalam jumlah ruang terkecil. Merekomendasikan fungsi global dalam sebuah header (bukan inline statis?) Akan memecah kode dengan 2+ unit kompilasi, bahkan tidak mengkompilasi, menamai fungsi seperti makro, tersirat int seperti 1989, mengembalikan ganda tanpa alasan lain, tersirat gips yang akan menyebabkan peringatan di terbaik ... dan yang paling penting ITU TIDAK JAWABAN PERTANYAAN - tidak generik, tidak aman dan paling jelas bukan cara terbaik
technosaurus
Masing-masing dari masalah tersebut perlu mendapat kritik lebih lanjut yang tidak dapat dicakup dalam detail yang cukup.
technosaurus