Comments 50
int Rand3() {
return rand2() | (rand2() << 1);
}
static int rand3() =>
(int) ((rand2() + rand2() * 2 + rand2() * 4 + rand2() * 8 + rand2() * 16 +
rand2() * 32 + rand2() * 64) / 128.0 * 3);
return (rand2() + rand2()+ rand2()+ rand2()+ rand2())%3
С чего бы? Ваши вероятности для того, что в скобках — такие:
1/32, 5/32, 10/32, 10/32, 5/32, 1/32
По модулю 3 получаются более равномерные, но все еще не равные вероятности:
11/32, 10/32, 11/32
int rand3()
{
switch (rand2().ToString() + rand2().ToString()) {
case "00":
return 0;
break;
case "01":
return 1;
break;
case "10":
return 2;
break;
case "11":
return rand3();
break;
default:
return rand3();
}
}
int rand3()
{
int v= (rand2() + rand2()) {
return v>2? rand3(): v
}
{
return rand2()+rand2();
}
1) детали имплементации рантайма .NET, есть еще Mono, еще есть Mono под LLVM, есть еще отнсительно новый RyuJIT
2) О май гад, делегат это тип, в рот мне тапки. В каждой книге по С# об этом говорят.
3) Дети, а теперь давайте поработаем интерпретатором
4) З — Замыкания. Надеюсь автор знал правильный ответ.
5) Хрен проссышь что там тильда а не минус, пятерочка за крипто-операторы вроде бинарного комплемента (~) и отрицания (!).
6) GC.Collect() нет смысла вызывать никогда
Тогда вопрос автору, как сделать каст без боксинга и создания новых объектов в выражении:
// не меняя сигнатуру естественно
public static int CastToInt<T>(T value)
{
return (?)value;
}
Согласен. Но примеры в статье не про хороший код.
3) комбинация делегатов и использования результата вызова комбинации делегатов
4) замыкания, неявное создание объектов в куче
5) использования редкого оператора, где его визуально можно спутать с другим оператором (-)
6) Явные вызок GC.Collect() плохо пахнет даже с отговорками
1) Возможно, интересно знать, но на практике есть этим знаниям применение? Не думаю… Меня как-то на собеседовании спросили, какой бит используется GC для маркировки обьекта после прохода по нему (при анализе, что нужно собрать). На кой, спрашивается, это нужно знать? Возможно, однажды, будет какой-то кейс где это может как-то пригодиться, но на такие случаи достаточно это один раз загуглить и забыть, а не держать такие знания в памяти…
4) Замыкание же. Обьезженая тема, как по мне. Главное понимать как это работает на практике, я думаю, а превращается ли это в отдельный клас в нутрях, важно ли это? Если да, то как часто?
Вообще, оглядываясь назад, на большинстве моих собеседований пытались узнать чего я не знаю, а не что мне известно. В большинстве ситуаций это просто было своего рода рычагом, чтобы снизить требуюмую изначально ЗП. Не так важно понимать, что человек знает, сколько что он может/умеет делать. Ведь не всегда наличие знаний подразумевает умение ними пользоваться… В этом контексте большинство нынешних собеседований не так показательны, к сожалению…
{
return (int)(dynamic)value;
}
Скомпилируется и скастит, скажем, double в int. Для остального (типа стринга) пошлёт с эксешпеном :)
Боксинг всё равно будет. Компилятор генерирует такой код:
public static int CastToInt<T>(T v)
{
if (Test.<>o__0<T>.<>p__0 == null)
{
Test.<>o__0<T>.<>p__0 = CallSite<Func<CallSite, object, int>>.Create(Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(int), typeof(Test)));
}
return Test.<>o__0<T>.<>p__0.Target(Test.<>o__0<T>.<>p__0, v);
}
Где Target
имеет тип Func<CallSite, object, int>
. А при первом вызове к тому же будут созданы новые объекты.
Аналог (int)(object)value
без боксинга будет таким:
public static int CastToInt2<T>(T v)
{
return __refvalue(__makeref(v), int);
}
Оба варианта работают только когда typeof(T) == typeof(int)
. Для непрямых приведений (например, из double к int) можно написать что-то вроде:
public static int CastToInt2<T>(T v)
{
if (typeof(T) == typeof(int))
return __refvalue(__makeref(v), int);
else if (typeof(T) == typeof(double))
return (int) __refvalue(__makeref(v), double);
// Similar conditions vor all possible casts
else
throw new InvalidCastException();
}
Других вариантов без лишних аллокаций нет.
На самом деле (int)(object)value
тоже может работать без выделения памяти, в зависимости от версии JIT. У меня получается такой код в x86 Release:
Для сравнения (object)value
:
А вот вариант с __refvalue(__makeref(v), int)
, тут кода уже больше и тоже есть внешний вызов:
Этот же код в x64 Release, (int)(object)value
опять побеждает:
Не зря говорят, что преждевременная оптимизация — корень всех зол.
Ему уже известно что вместо дженерика будет int, и кастить int в int он не будет.
Но, этот компилятор не будет, или в этой версии не будет. Это надежда на оптимизации компилятора. Не спорю что полезно о них знать, но оптимизации могут и не случиться, и приложение начнет засирать память.
Хотя наблюдение довольно интересное.
static class A
{
static Random r = new Random();
static int c = 0;
public static int rand3()
{
c = (c + 1) % 3;
while (r.Next(2) == 0)
c++;
return c % 3;
}
}
Проверка:
> Enumerable.Range(0, 10000).Select(_ => A.rand3()).GroupBy(_ => _).Select(g => g.Count()).ToArray()
int[3] { 3365, 3300, 3335 }
Спасибо за статью, полезно.
Предлогаю свое решения последнего вопроса.
int rand3() {
int r = rand2();
return r == 0? r: r + rand2();
}
Любые типы делегатов — это потомки класса MulticastDelegate, от которого
они наследуют все поля, свойства и методы.
Класс System.MulticastDelegate является производным от класса System.Delegate,
который, в свою очередь, наследует от класса System.Object. Два класса делегатов
появились исторически, в то время как в FCL предполагался только один.
public int rand3()
{
// 0 -> 0.5, 1 -> 0.5, 2 -> 0
var x = rand2();
// 0.5 * 0.5 = 0.25 -> 0, 1
if(x == rand2())
{
// 0.25 * 0.5 -> 0.75 = 1/3
return x == rand2() ? 2 : x;
}
return x;
}
Интересные вопросы на знание C# и механизмов .NET