Показаны сообщения с ярлыком just for fun. Показать все сообщения
Показаны сообщения с ярлыком just for fun. Показать все сообщения

четверг, 16 июня 2011 г.

Подзаголовок

Давно хотел себе в дневник какой-нибудь подзаголовок. Для развлечения сделал небольшой скрипт, который подставляет новый подзаголовок на каждый день.
Все-таки удобно, когда можно редактировать шаблон дневника на таком низком уровне.

четверг, 17 марта 2011 г.

пятница, 11 марта 2011 г.

вторник, 1 марта 2011 г.

Should I work for free? (по следам переводчика)

В продолжение поста о схеме "Стоит ли работать бесплатно?".
Недавно нашел еще один перевод этой же схемы на сайте allprosto.com:
 

В некотором смысле он более удачный, но не во всем. Во общем, смотрите сами.

воскресенье, 27 февраля 2011 г.

Should I work for free?

Не так давно Джессика Хисч (американский дизайнер и иллюстратор) выложила забавную схему под названием "Should I work for free?" Или, если по нашему - "Стоит ли работать бесплатно?"
К собственному и вашему развлечению я перевел ее и, вот, представляю вашему вниманию:

понедельник, 27 сентября 2010 г.

Программист или убийца?

Забавный тест (хоть и баян) на тему "кто-кого видит издалека".



Спасибо Александру за ссылку.

понедельник, 20 сентября 2010 г.

Вебкамера на орбите

Митч пишет, что на МКС установили веб-камеру.
Посмотреть на землю в режиме реального времени можно по ссылке:
mms://a1709.l1856953708.c18569.g.lm.akamaistream.net/D/1709/18569/v0001/reflector:53708
Этот адрес нужно задать любому плееру, поддерживающему потоковое вещание. Лично я воспользовался способом "Пуск - Выполнить" и вставил ссылку в строку команды. Медиа-плеер распознал и открыл ссылку.

Так же интересно было почитать блог космонавта, который он писал прямо с орбиты.

четверг, 26 августа 2010 г.

Условия и переменные (заметки Кэпа)

Решил я как-то проверить каким образом вычисляются составные условия в 1С 8.1
Не думаю, что профи найдут для себя в этой статье нечто новое или интересное, но Капитан Очевидность продолжает вещать.
Первое, что пришлось проверить - не инициализированные переменные:

На код вроде:
    А = 1;

    Если (
А=1) и (Б=1) Тогда
       
Сообщить("Ок!");
    КонецЕсли;

Выругался сам "компилятор" при попытке сохранить обработку. Логично, так как переменная Б нигде не определена. Но, если обмануть синтаксический контроль следующим образом:
    А = 1;

    Если
0=1 Тогда  // заведомо ложное условие
       
Б=1;        // никогда не выполняющийся код
   
КонецЕсли;

    Если (
А=1) и (Б=1) Тогда
       
Сообщить("Ок!");
    КонецЕсли;

В этом случае при сохранении ошибки синтаксиса не будет, а при запуске надписи "Ок!" не появляется. По логике следования кода мы нигде не определяли переменную Б, но код успешно выполняется.
Что говорит нам отладчик?
Обратите внимание, что в самом начале, когда ни одна переменная еще не определена память под них уже зарезервирована и им назначен тип "Неопределено", в отличии от переменной В, которая вообще не упоминается в процедуре.
Сделаем пару шагов:

Теперь все очевидно. Условие совершенно корректно и дает на выходе ложь, так как единица не равна "Неопределено" и вообще разных типов.

Итак, предварительный вывод:
Под переменные, которые могут быть инициализированы, внутри своей области видимости память выделяется в самом начале и они неявно инициализируются типом "Неопределено".

Чисто теоретически следующий код мог бы работать:
    А = 1;

    Если (
А=1) и (Б=1) Тогда
       
Сообщить("Ок!");
    КонецЕсли;

    Если
0=1 Тогда
       
Б=1;
    КонецЕсли;

Но нет. Не проходит синтаксический контроль, что вообщем-то правильно.

Чем же эта информация может быть полезна? Например тем, что если в процессе отладки у вас какая-то переменная имеет тип "Неопределено", то возможно она была инициализирована неявно и вам стоит проверить свои условия. Хотя, вносить инициализацию переменной в условие вообще-то плохой тон. Да, да, как раз из-за вышеизложенного.

Однако, неявная инициализация это не совсем то, что я собирался выяснить с самого начала и я вернулся к условиям.

Следующий код работает как положено и выдает правильный результат:
    Товар = Справочники.Номенклатура.НайтиПоКоду("00000026");

    Если  (
ТипЗнч(Товар) <> Тип("Неопределено")) и (Товар.Наименование = "Тест") Тогда
       
Сообщить("Ок!");
    КонецЕсли;

В описании функции "НайтиПоКоду" написано, что:
Если не существует ни одного элемента с требуемым кодом, то будет возвращена пустая ссылка.
Если код не задан, то будет возвращено Неопределено.
Если честно, я не смог сразу добиться от функции возврата значения "Неопределено" и потому поступил проще:
    //Товар = Справочники.Номенклатура.НайтиПоКоду("00000026");
   
Товар = Неопределено;

    Если  (
ТипЗнч(Товар) <> Тип("Неопределено")) и (Товар.Наименование = "Тест") Тогда
       
Сообщить("Ок!");
    КонецЕсли;

Запускаем - бинго! Все работает, несмотря на то, что в составном условии есть обращение к реквизиту переменной "Товар", к "Наименованию", которого у типа "Неопределено" быть не может.
Для проверки попробуем еще два вида условия:
1.
    Если  (ТипЗнч(Товар) <> Тип("Неопределено")) или (Товар.Наименование = "Тест") Тогда
2.
    Если (Товар.Наименование = "Тест") и (ТипЗнч(Товар) <> Тип("Неопределено")) Тогда

В первом случае мы поменяли "и" на "или" в условии, во-втором поменяли местами части условия.

В обоих случая при попытке выполнения мы получили сообщение об ошибке. Почему? Потому, что "компилятор" вычисляя выражение условия идет от начала к концу по-очереди вычисляя каждое вложенное выражение (по правилам арифметики, ага) и как только становится очевидно, что все выражение имеет определнный результат (истина/ложь) вычисление прекращается.

В нашем случае, когда мы сначала проверяли не является ли переменная "Товар" неопределенной и получали "ложь" смысл проверки остальных операндов утрачивался, так как в операции "И" достаточно одному операнду быть ложным, чтобы остальные можно было не проверять - все-равно конечный результат будет "ложь".

В первом случае, когда мы заменили "и" на "или" необходимость проверять все выражение возникла снова так как в определении "или" говорится, что истинным должен быть "хотя бы один" из операндов. Но пытаясь вычислить второй операнд мы сталкивались с ошибкой о которой я писал выше.

Во-втором варианте, результат выполнения так же изменился, несмотря на то, что операция "и" коммутативная. Теперь проверка начинала выполняться с первого, заведомо провального операнда.

Такое поведение, на мой взгляд оправдано и удобно. Сравните, например с похожим кодом в платформе 7.7:
    //Товар = СоздатьОбъект("Справочник.Номенклатура");
    //Товар.НайтиПоКоду(" 52200");
   
Товар = ПолучитьПустоеЗначение();

    Если (ПустоеЗначение(
Товар) = 0) и (Товар.Наименование = "Тест") Тогда
        Сообщить(
"Ок!");
    КонецЕсли;

В отличии от 8.1 он не будет работать, так как проверяются все операнды операции "и", а второй у нас будет выдавать ошибку.
 

Для платформы 7.7 пришлось бы применить следующее:
    Если (ПустоеЗначение(Товар) = 0) Тогда
        Если (
Товар.Наименование = "Тест") Тогда
            Сообщить(
"Ок!");
        КонецЕсли;
    КонецЕсли;

Что на мой взгляд является неоправданным (хоть и небольшим) усложнением структуры кода.

Итак, теперь вы можете смело записывать в одно условие конструкции, которые могут вызывать ошибки, в случае расхождения типов, главное не забывайте предварять их проверками на соответствие.

Спасибо за внимание и хорошего вам кода!

среда, 30 июня 2010 г.

Опять Manufactoria!

Никак не могу пройти один уровень в manufactoria. Грызу, как Рональдо мяч.

вторник, 1 июня 2010 г.

Manufactoria

Отличная игра для тренировки мозга - Manufactoria.
Машина тьюринга 4ever!!!

воскресенье, 23 мая 2010 г.

Школа программиста

По совету Александа зарегистрировался на сайте Школа программиста (ссылка на профиль есть в разделе "Ссылки"). Решать задачи и правда очень увлекательно, и теперь когда выпадает свободная минутка я обязательно захожу туда.

среда, 21 апреля 2010 г.

Волшебство n &= (n - 1);

Как всегда уважаемый Александр радует интересными вопросами. На этот раз это формализованное доказательство того, что следующая функция вернет количество единиц в числе переведенном в двоичную систему:

int bitcount (unsigned int n)  {
   int count = 0 ;
   while (n)  {
      count++ ;
      n &= (n - 1) ;
   }
   return count ;
}

Т.е. фактически количество итераций цикла, равно количеству единичных (не нулевых) бит.

Хоть я и не математик, но попробуем внимательнее взглянуть на код...

Выполнение цикла будет прервано когда n станет равным нулю. Я считаю что формула
n &= (n - 1);
вызванная в цикле, убирает из n единицы (в двоичном представлении) до тех пор пока их совсем не останется.

Попробую доказать.

Для начала рассмотрим операцию n-1. Что будет происходить с числом в двоичном представлении? При вычитании единицы с числом в двоичном виде произойдет следующее: первый с правого края единичный бит будет обнулен, а предшествующие ему нули инвертированы. Вот так:
xx...xx100...00 - 1 = xx...xx011...11
где x -произвольные биты в левой части числа.
Это можно доказать следующим образом (если это нужно). Любое число A можно представить в виде:
А = bx*2x+bx-1*2x-1+...+b1*21+b0*20
где x - порядок бита в двоичном представлении числа,
а bx - сам бит в позиции x.
Значит и единицу можно представить следующим образом:
1=(1*20)=(1*21-1*20)=(1*22-1*21-1*20)...
Предположим, что b0=1, тогда:
A - 1 = (bx*2x+bx-1*2x-1+...+b1*21+1*20) - (1*20) = (bx*2x+bx-1*2x-1+...+b1*21+0*20)

Т.е. мы видим, что на место b0 подставился ноль, т.е. первый единичный бит справа был обнулен. (желтым я подсветил части выражения, которые взаимоуничтожаются из за разности знаков)
Если же первый единичный бит справа это b1 то можно сделать другую подстановку:
A - 1 = (bx*2x+bx-1*2x-1+...+1*21+0*20) - (1*21-1*20) = (bx*2x+bx-1*2x-1+...+1*21+0*20) - 1*21 + 1*20 = (bx*2x+bx-1*2x-1+...+0*21+1*20+0*20) = (bx*2x+bx-1*2x-1+...+0*21+1*20)

Теперь в позиции b1 ноль, зато в позиции b0 - единица.
Для предположения, когда первый единичный бит это b2:
A - 1 = (bx*2x+bx-1*2x-1+...+1*22+0*21+0*20) - (1*22-1*21-1*20) = (bx*2x+bx-1*2x-1+...+1*22+0*21+0*20) - 1*22+1*21+1*20 = (bx*2x+bx-1*2x-1+...+0*22+1*21+1*20)

И так далее и тому подобное.
Не знаю, считаются ли мои корявые рассуждения доказательством у настоящих математиков, но отсюда во-всяком случае понятно что происходит: в битовом представлении числа самая правая единица превращается в ноль, а все остальное за ней превращается в единицы.

Следующая операция это побитовый И.

Что произойдет с числами А и B когда с ним будет произведена побитовая операция И, если мы знаем, что:
1. B = A - 1, а значит, что
2. До бита с номером Y эти числа совпадают.
3. Бит с номером Y - самая правая единица в числе A, за которым идут нули.
4. Сам бит с номером Y в числе A равен единице, а в B равен нулю и
5. далее в числе A все последующие символы равны нулю, а в B - единице.

Очевидно, что часть числа ДО бита с номером Y останется неизменной, так как a&a=a.
Бит с номером Y будет обнулен и так же будут обнулены все последующие за ним, так как там один из операндов равен нулю.

  xx...xx100...00 
& xx...xx011...11 =
  --------------- 
  xx...xx000...00

Т.е. мы видим, что в результате этой операции самый правый единичный бит в байте превратился в ноль.

Мы сможем повторять эту операцию и результат не будет равен нулю до тех пор, пока последний единичный бит не станет нулевым. Очевидно, что количество итераций и будет равно количеству единиц в числе.

Извините, если мое описание немного сумбурное, буду благодарен за подсказки о том "как правильно".

четверг, 8 апреля 2010 г.

Решение задачи о гномиках в разноцветных шапках

Александр выложил интересную задачу про гномиков.

Не придумал как вставить картинку к нему в каменты, поэтому решение привожу здесь.

Итак, вот схема:
[Image]
В первой строке отмечены номера гномиков (для удобства), во второй их реальное расположение. Гномики смотрят вправо, т.е. номер первый видит всех, последний никого. Далее идут шаги которые гномикам нужно предпринять, чтобы всем спастись (в колонках отмечено кто и что делает).

Итак, первый гномик делает операцию последовательного XOR-а. Т.е. он берет 2-го и 3-го гномика и проводит XOR, результат я записал в колонку G (под третьего гномика). После чего он берет результат и XOR-ти с 4-м (результат под 4-го), потом этот результат XOR-ит c 5-ым и т.д. В итоге он получает значение, которое и называет (отмечено желтым). В зависимости от того совпало оно или нет людоед его съедает или нет и тут работает чистая удача.

Но дальше, все уже знают конечный XOR последовательности и могут понять кто они. Например на шаге 3 второй гномик предполагает, что он 0 (отмечено голубым). Исходя из этого он проводит последовательный XOR (шаг 4) и получает в результате 0 (отмечено красным). Поскольку его результат не совпадает с начальным, который посчитал 1-й гномик  (желтым) он понимает, что предположение о том, что он 0 было не верным, а значит он 1. И на 5-м шаге говорит: 1. Дальше аналогично третий гномик делает предположение и считает XOR и т.д.

UPD.: (извините, нужно было убегать, потому набросал саму идею, теперь формализую)
Или, говоря строгим языком математики:
Обозначим состояние шапки каждого гномика как X. Тогда состояние шапки n-го гномика будет Xn. Пусть, для определенности, у черных шапок X=1, а для белых X=0.
Так же для определенности, пусть общее количество гномиков равно m.
Вначале первый гномик (который видит всех) должен вычислить "общий XOR" (обозначим его Z) последовательности гномиков по формуле:

Z1=(((X2 XOR X3) XOR X4) XOR X5) ... XOR Xm)

Полученный результат он называет и в зависимости от удачи людоед его съедает, либо нет. (Если Z1 совпало с X1, то, соответственно не съедает). Однако таким образом всем становится известно состояние X1.
Дальше каждый гномик делает предположение о своем состоянии (Xn) и вычисляет собственный "общий XOR" (Zn) по формуле:

Zn=(((Xn-1 XOR Xn) XOR Xn+1) XOR Xn+2) XOR Xn+3) ... XOR Xm)

Если Zn отличается от Z1 то это означает, что предположение гномика о собственном состоянии было ошибочным и он называет противоположное. При совпадении, соответственно, предположение считается верным и называется именно оно.

Таким образом все гномики начиная со 2-го назовут заведомо верные собственные состояния.

Задача решена.

воскресенье, 28 марта 2010 г.

Старый хлам в картонной коробке

Знаете, как обычно бывает, когда делаешь уборку и находишь коробку с разным старым хламом.
"Ну, вот я ее щас выкину, - думаешь. - Только погляжу что там лежит".
И вот тут уборка останавливается. Начинаешь доставать, разглядывать. А потом задвинешь ее обратно как есть, потому что жалко же выбрасывать, столько воспоминаний. Примерно тоже происходит и со старыми исходниками, разными файлами, старыми проектами. Набрел сегодня на такую свою "коробку" и кое-чем поделюсь с вами.

Lab_5_18
Когда-то я зарабатывал карманные деньги тем, что делал лабораторки для старшекурсников. Все это было, конечно, примитивно и скучно: работа с массивами, списками, основы языка... Но одна лабораторка мне нравится до сих пор. Каждый раз как запускаю умиляюсь, до чего хорошо получилось. Это парсер, который раскладывает арифметическое выражение в дерево:
Кстати, тут видно, что он не только строил дерево, но и немного сжимал его, избавляясь от сложения с нулем и подобных операций. Конечно, когда формула уже лежит в дереве, то работать с ней становится легко и приятно, можно применять разные шаблоны, тасовать узлы как угодно и получать просто восхитительные результаты. Например, формульный калькулятор в компилируемых языках. Думаю, что именно такой способ представления формул используется в каком-нибудь MathLab.

DemoAsm
Первая программа на ассемблере. Скомпилирована еще тогда, но до сих пор работает. Чего бы ей не работать. Собственно включает режим 0x13h и рисует желтую точку на экране. Управлять точкой можно с помощью клавиш q,a,o,p, выход - Esc. Скриншот, к сожалению, не делается. Кстати! Размер EXE-шника всего 956 байт.Т.е. меньше килобайта. Нет, все-таки в ассемблере что-то есть.

Fistpath
Патчер для какой-то из версий игры "Элита" (кажется First Encounters). Добавлял произвольное количество денег. Кажется, речь шла о "стартовых" деньгах.
Патчер примечателен тем, что в нем переопределялся знакогенератор для режима 0x03h и менялась палитра. За счет этого достигался эффект плавной бегущей строки (в текстовом режиме) и плавного появления/исчезновения звезд на фоне. Тут я тоже не осилил сделать скриншот, но вы можете посмотреть сами.

WinKley
Софтина задумывалась как "клей" для windows-программ. По-идее должна была "склеивать" два EXE-шника в один таким образом, чтобы сначала загружался один, а за ним другой. Сам клей реализован так и не был, но зато получился симпатичный интерфейс (нужно помнить, что речь идет о времени, когда WinXP с ее красивыми темами еще не вышла). Он весь подсвечивается и подзвучивается при наведениях и нажатиях. Кстати, что-то оно с EXE-шниками все же делает, во всяком случае мой антивирус ругается на Output file.

Kt
Электронный камертон. Ничего необычного, просто пищит через PC-спикер. Замечательно то, что тут используется библиотека sCrt. Это моя собственная библиотека (очень примитивная надо отметить, были намного профессиональнее) упрощающая построение интерфейса в стиле Norton. Тогда это, был самый популярный пользовательский интерфейс для DOS-приложений. Кажется это было одно из последних приложений под DOS. Все-таки 2001-год, я уже писал под Windows.

Poin1
После запуска на экран будет выведено несколько точек, а после нажатия клавиши точки будут обведены в многоугольник, причем так, что крайние точки станут его вершинами, а все остальные окажутся внутри. Т.е. многоугольник как бы "обтянет" эти точки. Такой же эффект, как если бы вы бегали с ниткой вокруг группы деревьев, некоторые оказались бы внутри ниточного ограждения, а на некоторые (самые внешние) оказались бы в вершинах ниточного многоугольника.
Вообще-то Poin1 это часть общей задачи которая изначально решалась в 3D для точек и многогранника. Это же ее разновидность для плоскости.

Matrix
Не думаю, что нужно объяснять что именно делает эта программа. Совершенно ничего особенного. Обычный Screen saver. Таких были сотни разновидностей. Вот еще один для DOS-а. Да, я немного подправил его сегодня, поставлял задержек, чтобы на современной машине можно было хоть что-то разглядеть.

Вот, собственно, и все что нашлось из интересного. А еще больше было потеряно, стерто и отформатировано. Мои эксперименты с 3D, куча разных мелких утилит под Windows и еще много чего.

Естественно, выкладываю все файлы (с исходниками) в архиве: old_prog.zip

четверг, 7 января 2010 г.

Тень легче и светлее. И дальше?

Недавно я писал пост об Эйфелевой башне. Как вполне справедливо заметил Алексей, я не учел в расчетах того, что тень от башни не абсолютно черная, но слегка серая от отраженного и рассеянного света. Если честно, я ума не приложу где можно было бы найти коэффициент, описывающий отличие "настоящей" тени погожий в летний день, от абсолютно черной тени. Можно было бы самому поставить опыт, но опять-таки, не совсем понятно с какой стороны подступиться, чтобы опыт был однозначным, не зависящим от качества светочувствительной техники.
Однако в Новый Год мне довелось познакомится с одним замечательным полиграфистом из Москвы. Конечно, он не дал мне готового коэффициента, но исходя из его опыта работы с изображениями, насыщенность тени на фото в летний день составляет от 60%-80% от абсолютно черного. Возьмем среднее - 70%. С учетом этой поправки вес будет равен 2,95г. (70% от 4,22г.)

Еще во всей этой истории интересно то, что многие люди считают, что тень от очень высокого предмета неоднородна. И что она становится светлее ближе к вершине. Очевидно, что если рассматривать солнце как источник параллельных лучей, такого быть не может. Но заблуждение (заблуждение?) очень стойкое, воспринимаемое людьми как нечто очевидное.Чудно.

четверг, 24 декабря 2009 г.

Развлечемся с Эйфелевой башней?

- Что такое: большое, как Эйфелева башня, а не весит ни грамма?
- Тень от Эйфелевой башни.
(шуточный вопрос)


Когда я попался на эту старую штуку я подумал: "Черт, возьми! Неужели тень от башни действительно ничего не весит?"
Формально, оно, конечно так. Невозможно взвесить тень. Однако, если бы мы "положили" тень на сверхточные весы, что бы мы получили в итоге? Качнулась бы стрелка весов? Возможно.

Пожалуй, стоит начать с того, что все предметы освещенные солнцем испытывают на себе давление солнечного света. Значит, в том месте, куда солнечный свет не попадает, давление он не оказывает. Т.е., если бы на одну чашу весов мы "положили" бы тень от башни, а на другую такую-же (естественно освещенную солнцем) не "положили", то стрелка должна была бы сдвинуться в сторону освещенной чаши, говоря о том, что тень "весит" минус сколько-то. Итак, сколько же?

Максвелл вычислил, а Лебедев подтвердил, что на земле давление солнечного света равно всего лишь 4,7*10-6 Н/м2, но эта величина справедлива для света падающего перпендикулярно на идеально отражающую поверхность.

Если же солнце находится на высоте α (от 0° - у горизонта до 90° - в зените), то силу действующую в направлении нормали (собственно силу давления на весы) мы легко вычислим по формуле: Fn=F*sin(α)

Теперь для конкретики нам придется определиться с положением солнца. Поэтому, давайте решим для себя, что мы "взвешиваем" тень от Эйфелевой башни 01.07.2010 в 12:00 по местному времени.

Итак, для этого времени (и места) легко узнать положение солнца над горизонтом при помощи Excel-калькулятора (на самом деле можно было воспользоваться online-калькулятором, но он не учитывает переход на летнее время, поэтому для него вы должны будете сделать корректировку времени на час назад).

Введя координаты (Википедия дает нам следующие данные: 48°51'29''с.ш. / 2°17'40''в.д. или в дробных градусах 48.858056°с.ш. / 2.294444°в.д.) и время мы получим:

Sun's Azimuth
-51,59930886°
-51°35'58''
True (Celestial) Altitude of sun
55,73861046°
55°44'19''
Apparent (Refracted) Altitude of sun
55,75011692°
55°45'00''

Где Sun's Azimuth это направление на солнце (величина показывает угол отклонения от направления на юг и, так как она отрицательная, то это отклонение в восточную сторону, т.е. если в это время стать лицом на север, то солнце будет светить в попу, приятно обогревая правое ухо).
А Altitude of sun это как раз и есть высота солнца над горизонтом. Причем True (Celestial) Altitude - действительная, а Apparent (Refracted) Altitude кажущаяся высота, которая отличается от действительной за счет того, что лучи света немного преломляются при входе в атмосферу. Несмотря на то, что разница небольшая, лучше будет взять кажущуюся высоту.

Итак, угол известен: 55,75011692°

Осталось вычислить площадь тени Эйфелевой башни. Как это сделать? Специально для этого я скачал ее трехмерную модель. Возможно, точности этой модели недостаточно, но в случае крайней необходимости можно будет создать или найти более точную модель. Пока же ограничимся этой.

Очистив сцену от ненужных декораций я получил вполне приличный результат:



Дальше, спозиционируем башню относительно сторон света так, как она установлена в реальности:



Теперь добавим параллельный источник света с нужными координатами (высота и азимут) и получим... Получим... Правильно! Тень от башни:



Пока нам нет никакой пользы от такой картинки, однако путем небольших манипуляций (скрываем саму башню, делаем плоскость белой и включаем ортогональную проекцию - вид сверху) мы можем получить то, что нам действительно может пригодиться:






Теперь используя этот рисунок несложно подсчитать какой процент площади зеленого прямоугольника занимает тень от башни на рисунке (назовем этот коэффициент sh). А вычислив реальную площадь такого же прямоугольника у настоящей башни, мы путем умножения на коэффициент, узнаем реальную площадь, которую занимает тень.

Итак, несложная программка, считающая черные точки выдала коэффициент sh=0,38579 (естественно, я использовал картинку с большим разрешением, чем выкладываю в web).

Теперь о реальной площади прямоугольника. Согласно размерам башни ширина меньшей стороны прямоугольника будет равна 124,9 м. (ширина основания башни). И, раз уж так получилось, что башня почти "стоит лицом" к солнцу, то для упрощения будем считать что большая сторона прямоугольника равна сумме длин синего и желтого отрезков (там действительно не очень большой угол отклонения от стороны и погрешность будет невелика). Длина желтого отрезка равна половине ширины основания башни, а длина синего вычисляется по формуле: x=H*ctg α
Где H - высота башни, α - высота солнца над горизонтом.
Получаем, что x=221,28 м

Значит, площадь прямоугольника 221,28 * 124,9=27637,87 м2

Теперь применим коэффициент sh и получим, что площадь тени:
27637,87 м2 * 0,38579 = 10662,41 м2

Теперь, когда мы знаем высоту солнца, по формуле Fn=F*sin(α) посчитаем силу действующую на каждый метр:
4,7*10-6 Н/м2 * sin(55,75011692°) = 3,88*10-6 Н/м2

И умножим на площадь тени:
10662,41 * 3,88*10-6 = 41,37*10-3 Н/м2

Что равно силе с которой груз массой 4,22 грамма давит на плоскость.

Так, что шутник из эпиграфа к этому посту сильно ошибался. Тень от башни "весит" минус четыре грамма!

P.S.: Пост писался исключительно ради развлечения, так что в нем, естественно, могут быть ошибки или неточности. Если вы найдете таковые пишите, буду рад. Кстати, никто не знает лучшего метода вычисления площади тени башни?