Чтобы избежать всех отрицательных эффектов инициализации двойной комбинации, например:
делать следующие вещи:
Пример:
public class MyClass {
public static class Builder {
public int first = -1 ;
public double second = Double.NaN;
public String third = null ;
public MyClass create() {
return new MyClass(first, second, third);
}
}
protected final int first ;
protected final double second;
protected final String third ;
protected MyClass(
int first ,
double second,
String third
) {
this.first = first ;
this.second= second;
this.third = third ;
}
public int first () { return first ; }
public double second() { return second; }
public String third () { return third ; }
}
Использование :
MyClass my = new MyClass.Builder(){{ first = 1; third = "3"; }}.create();
Преимущества:
Недостатки:
И, как результат, у нас самый простой шаблон java-строителя.
См. все образцы в github: java-sf-builder-simple-example
Используйте по модулю (%) оператор, чтобы проверить, существует ли остаток при делении на 2:
if (x % 2) { /* x is odd */ }
Несколько человек подвергли критике мой ответ выше утверждения того использования x & 1 "быстрее" или "более эффективен". Я не полагаю, что это имеет место.
Из любопытства, я создал две тривиальных программы тестового сценария:
/* modulo.c */
#include <stdio.h>
int main(void)
{
int x;
for (x = 0; x < 10; x++)
if (x % 2)
printf("%d is odd\n", x);
return 0;
}
/* and.c */
#include <stdio.h>
int main(void)
{
int x;
for (x = 0; x < 10; x++)
if (x & 1)
printf("%d is odd\n", x);
return 0;
}
я тогда скомпилировал их с gcc 4.1.3 на одной из моих машин 5 различных раз:
я исследовал вывод блока каждой компиляции (использующий gcc-S) и нашел, что в каждом случае, вывод для and.c и modulo.c был идентичен (они оба использовали andl 1$, %eax инструкция). Я сомневаюсь, что это - "новая" функция, и я подозреваю, что она относится ко времени древних версий. Я также сомневаюсь относительно любого современного (сделанный за прошлые 20 лет), нетайный компилятор, коммерческий или с открытым исходным кодом, испытывает недостаток в такой оптимизации. Я протестировал бы на других компиляторах, но я не имею никого в наличии в данный момент.
, Если бы кто-либо еще хотел бы протестировать другие компиляторы и/или цели платформы, и получает различный результат, мне очень было бы интересно знать.
Наконец, версия по модулю , гарантировал по стандарту, чтобы работать, положительно ли целое число, отрицательно или нуль, независимо от представления реализации целых чисел со знаком. Поразрядное - и версия не. Да, я понимаю, что дополнение two несколько повсеместно, таким образом, это не действительно проблема.
Если Вы хотите быть эффективными, используйте побитовые операторы (x & 1
), но если Вы хотите быть читаемым использованием по модулю 2 (x % 2
)
Ради обсуждения...
только необходимо посмотреть на последнюю цифру в любом данном числе, чтобы видеть, даже ли это или нечетно. Со знаком, неподписанный, положительный, отрицательный - они являются всеми одинаковыми относительно этого. Таким образом, это должно работать повсюду вокруг: -
void tellMeIfItIsAnOddNumberPlease(int iToTest){
int iLastDigit;
iLastDigit = iToTest - (iToTest / 10 * 10);
if (iLastDigit % 2 == 0){
printf("The number %d is even!\n", iToTest);
} else {
printf("The number %d is odd!\n", iToTest);
}
}
ключ здесь находится в третьей строке кода, оператор деления выполняет целочисленное деление, так, чтобы результат пропустил дробную часть результата. Так, например, 222 / 10 даст 22 в результате. Тогда умножьте его снова с 10, и Вы имеете 220. Вычтите это из оригинала 222, и Вы заканчиваете с 2, который волшебством является тем же числом как последняя цифра в исходном числе.;-) круглая скобка там для напоминания нам о порядке, в вычислении выполняют. Сначала сделайте разделение и умножение, затем вычтите результат исходного числа. Мы могли пропустить их, так как приоритет выше для разделения и умножения, чем вычитания, но это дает нам "больше читаемого" кода.
Мы могли сделать все это абсолютно нечитабельным, если бы мы хотели. Это не имело бы никакого значения вообще для современного компилятора: -
printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");
, Но это сделало бы код путем тяжелее для поддержания в будущем. Просто предположите, что требуется измениться, текст для нечетных чисел к "даже не". Тогда кто-то еще позже хочет узнать то, что изменяет Вас сделанный, и выполните svn разность или подобный...
, Если Вы не волнуетесь по поводу мобильности, но больше по поводу скорости, Вы могли бы взглянуть на наименее значимый бит. Если тот бит установлен на 1, это - нечетное число, если это 0, это - четное число. В небольшой системе порядка байтов как x86 архитектура Intel это было бы что-то вроде этого: -
if (iToTest & 1) {
// Even
} else {
// Odd
}
Портативный:
i % 2 ? odd : even;
Непортативный:
i & 1 ? odd : even;
i << (BITS_PER_INT - 1) ? odd : even;
IsOdd (интервал x) {возвращают true;}
Доказательство правильности - рассматривает набор всех положительных целых чисел и предполагает, что существует непустое множество целых чисел, которые не нечетны. Поскольку положительные целые числа упорядочены, будет самое маленькое не нечетное число, которое сам по себе довольно нечетно, настолько ясно, что число не может быть в наборе. Поэтому этот набор не может быть непустым. Повторитесь для отрицательных целых чисел кроме, ищут самое большое не нечетное число.
Поразрядный метод зависит от внутреннего представления целого числа. По модулю будет работать где угодно существует оператор по модулю. Например, некоторые системы на самом деле используют низкоуровневые биты для меток (как динамические языки), таким образом, сырые данные x & 1 не будет на самом деле работать в этом случае.
В "творческой, но запутывающей категории" я предлагаю:
int isOdd(int n) { return n ^ n * n ? isOdd(n * n) : n; }
вариант А на этой теме, которая характерна для Microsoft C ++:
__declspec(naked) bool __fastcall isOdd(const int x)
{
__asm
{
mov eax,ecx
mul eax
mul eax
mul eax
mul eax
mul eax
mul eax
ret
}
}
Я знаю, что это - просто синтаксический сахар и только применимый в .net, но что относительно дополнительного метода...
public static class RudiGroblerExtensions
{
public static bool IsOdd(this int i)
{
return ((i % 2) != 0);
}
}
Теперь можно сделать следующий
int i = 5;
if (i.IsOdd())
{
// Do something...
}
// C#
bool isEven = ((i % 2) == 0);
Еще одно решение проблемы
(дети могут голосовать)
bool isEven(unsigned int x)
{
unsigned int half1 = 0, half2 = 0;
while (x)
{
if (x) { half1++; x--; }
if (x) { half2++; x--; }
}
return half1 == half2;
}
Я сказал бы, просто делят его на 2 и если существует 0 остатков, это даже, иначе это нечетно.
Используя модуль (%) делает это легким.
, например, 4% 2 = 0 поэтому 4 даже 5% 2 = 1 поэтому 5, нечетен
Число - то, даже если, когда разделено на два, остаток 0. Число нечетно, если, когда разделено на 2, остаток равняется 1.
// Java
public static boolean isOdd(int num){
return num % 2 != 0;
}
/* C */
int isOdd(int num){
return num % 2;
}
Методы являются замечательными!
Хороший:
/*forward declaration, C compiles in one pass*/
bool isOdd(unsigned int n);
bool isEven(unsigned int n)
{
if (n == 0)
return true ; // I know 0 is even
else
return isOdd(n-1) ; // n is even if n-1 is odd
}
bool isOdd(unsigned int n)
{
if (n == 0)
return false ;
else
return isEven(n-1) ; // n is odd if n-1 is even
}
Примечание, что эта хвостовая рекурсия использования метода, включающая две функции. Это может быть реализовано эффективно (превратился, в то время как/до вид цикла), если Ваш компилятор поддерживает хвостовую рекурсию как компилятор Схемы. В этом случае стек не должен переполняться!
В ответ на ffpf - у меня был точно тот же спор с коллегой несколько лет назад, и ответ никакой , это не работает с отрицательными числами.
стандарт C предусматривает, что отрицательные числа могут быть представлены 3 способами:
, Проверяющая как это:
isEven = (x & 1);
будет работать на 2's дополнение и подписываться и представление величины, но не для 1's дополнение.
Однако я полагаю, что следующее будет работать на все случаи:
isEven = (x & 1) ^ ((-1 & 1) | ((x < 0) ? 0 : 1)));
<глоток> Благодаря ffpf для указания, что текстовое поле ело все после моих меньше, чем символ! глоток>
[Режим Joke = "на"]
public enum Evenness
{
Unknown = 0,
Even = 1,
Odd = 2
}
public static Evenness AnalyzeEvenness(object o)
{
if (o == null)
return Evenness.Unknown;
string foo = o.ToString();
if (String.IsNullOrEmpty(foo))
return Evenness.Unknown;
char bar = foo[foo.Length - 1];
switch (bar)
{
case '0':
case '2':
case '4':
case '6':
case '8':
return Evenness.Even;
case '1':
case '3':
case '5':
case '7':
case '9':
return Evenness.Odd;
default:
return Evenness.Unknown;
}
}
[Режим Joke = "прочь"]
РЕДАКТИРОВАНИЕ: Добавленные запутывающие значения к перечислению.
Использование укусило арифметику:
if((x & 1) == 0)
printf("EVEN!\n");
else
printf("ODD!\n");
Это быстрее, чем использование подразделения или модуля.
Вы парни waaaaaaaay слишком эффективный. То, что Вы действительно хотите:
public boolean isOdd(int num) {
int i = 0;
boolean odd = false;
while (i != num) {
odd = !odd;
i = i + 1;
}
return odd;
}
Повторение для isEven
.
, Конечно, который не работает на отрицательные числа. Но с блеском прибывает жертва...
Я бы построил таблицу четностей (0, если даже 1, если нечетное) целых чисел (чтобы можно было сделать поиск: D), но gcc не позволяет мне создавать массивы таких размеров:
typedef unsigned int uint;
char parity_uint [UINT_MAX];
char parity_sint_shifted [((uint) INT_MAX) + ((uint) abs (INT_MIN))];
char* parity_sint = parity_sint_shifted - INT_MIN;
void build_parity_tables () {
char parity = 0;
unsigned int ui;
for (ui = 1; ui <= UINT_MAX; ++ui) {
parity_uint [ui - 1] = parity;
parity = !parity;
}
parity = 0;
int si;
for (si = 1; si <= INT_MAX; ++si) {
parity_sint [si - 1] = parity;
parity = !parity;
}
parity = 1;
for (si = -1; si >= INT_MIN; --si) {
parity_sint [si] = parity;
parity = !parity;
}
}
char uparity (unsigned int n) {
if (n == 0) {
return 0;
}
return parity_uint [n - 1];
}
char sparity (int n) {
if (n == 0) {
return 0;
}
if (n < 0) {
++n;
}
return parity_sint [n - 1];
}
Так что давайте вместо этого прибегнем к математическому определению четного и нечетного.
Целое число n есть даже в том случае, если существует такое целое число k, что n = 2k.
Целое число n является нечетным, если существует целое число k такое, что n = 2k + 1.
Вот его код:
char even (int n) {
int k;
for (k = INT_MIN; k <= INT_MAX; ++k) {
if (n == 2 * k) {
return 1;
}
}
return 0;
}
char odd (int n) {
int k;
for (k = INT_MIN; k <= INT_MAX; ++k) {
if (n == 2 * k + 1) {
return 1;
}
}
return 0;
}
Пусть C-целые числа обозначают возможные значения int
в данной компиляции C. (Обратите внимание, что C-целые числа - это подмножество целых чисел.)
Теперь можно беспокоиться, что для данного n в C-целых числах соответствующее целое число k может не существовать в C-целых числах. Но с небольшим доказательством можно показать, что для всех целых n, | n | <= | 2n | (*), где | n | равно "n, если n положительно, и -n в противном случае". Другими словами, для всех n в целых числах выполняется хотя бы одно из следующего (на самом деле, либо случаи (1 и 2), либо случаи (3 и 4), но я не буду это здесь доказывать):
Случай 1: п <= 2n.
Случай 2: -n <= -2n.
Случай 3: -n <= 2n.
Случай 4: n <= -2n.
Теперь возьмем 2k = n. (Такой ak действительно существует, если n четно, но я не буду здесь это доказывать. Если n не четное, то цикл в даже
все равно не возвращается раньше, поэтому это не имеет значения.) это означает, что k
Аналогичное рассуждение показывает, что если n нечетно, существует ak в C-целых числах такое, что n = 2k + 1.
Следовательно, функции четные
и нечетные
представлены здесь будет работать правильно для всех C-целых чисел.