25 Ağustos 2017 Cuma

AVL Tree - Self Balancing Bir Binary Tree'dir

Giriş
Kısaca 
1. AVL Tree bir Binary Search Tree'dir
2. Self Balancing Search Tree olduğu için bir işlemden sonra herhangi bir düğümün sol veya sağ tarafının alt derinliği 1'den fazlaysa kendisini tekrar dengeler.
3. AVL Tree aynı Red-Black Tree gibi sadece bellekte saklanır

Açıklaması şöyle
In an AVL tree, for every node v, the difference between the height of v's right sub-tree and the height of v's left sub-tree must be at most 1.
1. Binary Tree Özelliği
AVL ağacı ikilik ağaç olduğu için yapısı şöyledir.
struct node {
  struct node *left; 
  struct node *right 
  ...
}  
2. Self Balancing Özelliği
Bir düğümün sol tarafının derinliği ile sağ tarafının derinliğinin farkı en fazla 1 olan ağaçtır. Kısaca her zaman dengeli olan ağaçtır. 

Örnek
Elimizde en son ekleme işlemi ile dengesiz hale gelene bir ağaç olsun.
  4
/   \
1    11
    /
   7
 /  \
5    9
AVL algoritması bu ağacı dengeli hale getirir. Şöyle yaparız.
    11
   /   \
  4    7
 /    / \
1    5   9

24 Ağustos 2017 Perşembe

Time Sheet

Giriş
Time sheet bir çok şirkette insanların hangi alanlara vakit harcadıklarını ölçmek için kullanılır.

Development - Yazılım geliştirme
Project Management Activities - Toplantılar
Official Leave - Resmi tatil
Unofficial Leave - Yıllık izin
Test - Test faaliyetleri

23 Ağustos 2017 Çarşamba

Bluetooth

Giriş
Bluetooth wi-fi bağlantısına göre çok daha yavaştır. Protokol paketlerini de çıkarttıktan sonra 2.1 Mbps civarında bir hız sunar. Hızı yavaş olduğu için de daha az enerji harcar.

Bluetooth 2.4 GHz taşıyıcı frekansını kullanır. Anteni omni-directional'dır yani her yöne yayın yapar. Diğer frekanslardan etkilenmemek için antenleri genelde bandpass filter içerir.

Bluetooh adresleri aynı MAC adresleri gibidir. MAC-48 şeklinde formatlanır.

Menzili 700-800 metreye kadar çıkabilir.

Open Systems Interconnection - OSI
Bluetooth'un OSI mimarisinde Layer 2'ye kadar gittiğini düşünüyordum ancak anlaşılan Layer 6'ya kadar herşeyi tanımlamış. Açıklaması şöyle
Bluetooth and it's low energy variant however are actually protocol stacks that go up to the presentation layer.
Pairing
Açıklaması şöyle
It's not possible to spoof a paired Bluetooth device. The Bluetooth peripheral and the phone exchange keys as part of the pairing process, so both of them can securely identify the other. When the devices connect, they each challenge the other to prove they have the secret keys. If it didn't work this way, it would be trivial to "man-in-the-middle" attack the connection by pretending to be the peripheral. Then the attacker could eavesdrop your phone calls or music, or whatever it is you're sending over Bluetooth.

22 Ağustos 2017 Salı

GoF - State Örüntüsü (Durum Makinesi)

Not : GoF Tasarım Örüntüleri yazısına bakabilirsiniz.

Örnek
IActivityHandler, state'e IActivityEvent gelince çalışacak kodu belirtir. State değişmez. Şöyle yaparız
public interface IActivityHandler<T extends IActivityEvent>{

  void perform (T event, IEventQueue queue);
}
IStateChangeHandler, state'in ITransitionEvent gelince state girişinde ve çıkışında çalışacak kodu belirtir. Şöyle yaparız
public interface IStateChangeHandler{

  void onEnter (State fromState, State totate, IEvent event, IEventQueue queue);

  void onExit (State fromState, State toState, IEvent event, IEventQueue queue);

}
ITransitionAction transition çalışınca çalışacak kodu belirtir. Şöyle yaparız
public interface ITransitionAction{

  void perform (Transition source, IEvent event);
}
Kuyruk için şöyle yaparız
public class FSMEventQueue : IEventQueue {

  private Queue<IEvent> queue = new LinkedList<>();

  private FSM fsm;


  @Override
  public void postEvent(IEvent event){
    eventQueue.offer(event);
    processEvents();
  }


  protected void processEvents(){
    while(!eventQueue.isEmpty()){
      IEvent event = eventQueue.poll();
      fsm.handleEvent(event);
    }
  }
}
FSM için şöyle yaparız
public class FSM{

  private IEventQueue queue = new FSMEventQueue();

  private Map<String, State> states = new LinkedHashMap();

  private State currentState;


  public void addState(State state){
    states.put(state.getIdentifier(),state);
  }


  //Bu kod aslında başka bir yardımcı sınıfta da olabilirdi
  public addTransition (State fromState, State toState, Object eventType,
    ITransitionAction action){
    Transition transition = new Transition (fromState,toState,eventType,action))
    fromState.addTransiton(transition);
  }


  public void handleEvent(IEvent event){

    if (event instanceof IActivityEvent){
      ActivityEvent activityEvent = (ActivityEvent)event;
      currentState.handleActivityEvent(activityEvent,queue);

    } else if (event instanceof ITransitionEvent){

      ITransitionEvent transitionEvent = ITransitionEvent)event;
      Object eventType = transitionEvent.getEventType();
      Transition transition = currentState.getTransition(eventType);
      currentState = transition.performTransition(transitionEvent,queue);

    }
  }
}
State için şöyle yaparız. eventType olarak Object kullanılıyor. Mesela eğer istersek hep String geçebiliriz.
public class State{

  private HashMap<Object,Transition> transition = new HashMap<>();

  private IActivityHandler activityHandler;

  private IStateChangeHandler stateChangeHandler;

  public void addTransition(Transition transition, Object eventType){
    transitions.put(eventType,transition);
  }


  public Transiton getTransition(Object eventType){
    return transitions.get(eventType);
  }


  public handleActivityEvent(IActivityEvent event, IEventQueue queue){
    activityHandler.handleActivity(event,queue);
  }

  public void onEnter(State fromState, IEvent event,IEventQueue queue){
    stateChangeHandler.onEnter(fromState,this,event,queue);
  }


  public void onExit(State toState, IEvent event,IEventQueue queue){
    stateChangeHandler.onEnter(this,toState,event,queue);
  }
}
Transition için şöyle yaparız
public class Transition{

  State fromState;

  State toState;

  Object eventType;

  ITransitionAction transitionAction;

  public State performTransition(ITransitionEvent event, IEventQueue queue){
    fromState.onExit(toState,event,queue);
    transitionAction.perform(event);
    toState.onEnter(fromState,event,queue);
    return toState;
  }
}
State - Davranışsal Örüntü
Tasarım örüntülerinde gösterilen state machine aslında Moore Machine, çünkü he bir state'in ismi var. State örüntüsünü kullanmadan önce aşağıdaki örnekte görüldüğü gibi bir modemi kontrol etmek için switch/case'ler kullanılabilir. Ancak bir miktar global değişken kullanmak gerekebilir.
switch(stage){
   case Power:
      powerOn();                 // Turn the modem on
      nextstage = ResetCmd;      // Go perform a reset
      attemptsLeft = 5;          // Send the reset command up to five times
      break;
   case ResetCmd;
      modem.write("ATZ\n");      // ATZ - reset
      attemptsLeft--;            // Use one of our attempts
      nextstage = ResetReply;    // Next wait for a response (should be OK)
      timeout = millis() + 5000; // Wait for up to 5 seconds each attempt
      break;
   case ResetReply;
      if(receivedResponse() == OK)     // Success
      {
         nextStage = NetworkAttachCmd; // Attach to the cellular network
      } elseif(receivedResponse() == ERROR || timeout < millis())
      {  // If we get an error or timeout, reattempt if we can, power on if we can't
         if(attemptsLeft > 0)
         {
            nextStage = ResetCmd;
         } else {
            nextStage = Power;
         }
      } 
      break;
   case NetworkAttachCmd:
   ...
}
stage = nextstage;        
Kod karmaşıklaştıkça global değişkenlerden kurtulmak ve daha anlaşılır hale getirmek için bu örüntüye ihtiyaç duyuluyor.

Current State
State örüntüsünde içinde bulunan state kutusuna "current state" ismi verilir.

State Metodları
Bir state OnEnter (), Process (), OnExit gibi metodlarsa sahip olabilir. Bu metodlar state'in hangi transition yolunu kullanarak değiştiğine bakmaksızın çalışır. Yani A'dan B'ye geçiş veya A'dan C'ye geçiş farketmez.
interface IState {
  void OnEnter
  void Process
  StateEnum OnExit
}

StateManager::Initialize (){
  stateList.Add (new InitialState (), INITIAL_STATE);
  stateList.Add (new AwaitingState (), AWAITING_STATE);
  ...
  currentState = stateList [ INITIAL_STATE ];

}

StateManager::Run () {
  currentState -> OnEnter (); // Do something
  currentState -> Process ();  //Do actual work
  SetNextState (currentState -> OnExit ()); // Decide which state is next
}

StateManager::SetNextState (StateEnum value) {
  currentState = stateList [ value ];
}
Bir State'ten Diğerine Geçmek - Transition
Bir state'ten diğerine geçmek için harici (external) veya dahili (internal) bir olayın (event) olması gerekir.

Bazı daha karmaşık State örüntüsünden bir state'ten birden fazla state'e geçiş olabiliyor. Bu durumda state kendi içinde bir Transition listesi tutar. Transition sınıfı şöyledir
class Transition {
  State FromState;
  State ToState;
}
StateManager şöyle yapar.
StateManager::Run (IEvent event) {
  Transition transition = currentState->GetTransition (event);
  currentState = transition.transit (event)
}
Transition çıktığı state'in OnExit(), girdiği state'in OnEnter() metodunu çağırır. Ayrıca Transition perform() metoduna da sahip olabilir. Böylece sadece belli bir yolu izlerken bazı işler yapılabilir. Yani sadece A'dan B'ye geçiş durumnda bir kod çalıştırabiliriz. A'dan C'ye geçişte ise çalıştırmayız.

StateEventQueue
Bazen state geçişleri olan event'lerin başka bir thread'den gelmesi ve asenkron olarak işlenmesi gerekir. Bu durumda event'ler bir kuyruğa konulur ve bu kuyruğu bir thread boşaltıp StateManager'ı çağırır.

Harici Olay
Harici olay dışarıdan gelen bir girdidir. Harici olay current state'e StateManager tarafından iletilir. Harici olayın bir event hiyerarşisinden türemesi iyi bir tasarımdır. Böylece her olay için state arayüzü değişmez. Current State olayı işledikten sonra bir sonraki state'i StateManager'a döndürür. Buraya kadar olan kısım kolay.

Dahili Olay
Dahili geçiş ise genelde bir timer aracılığıyla olur. State bir işlem başlatır ve beklemeye başlar. Bekleme süresi sonunda istenilen netice elde edilmemişse, bir başka state'e geçmek gerekir. İşte bu durumda State kendisini içeren StateManager veya StateContext isimli sınıfa çağrı yapar ve bir sonraki geçilmesi gereken state'i bildirir.

Genel Transition Kararları
Gelen girdiye göre içinde bulunulan state bir sonraki state'e karar verir. Bazen aksiyon state'lerinden önce READY state'leri koymak faydalı olabilir. Böylece gerekli mantık kontrollerin yapıldığından emin olunur.


STOPPED -> READY_TO_WASH -> WASHING

Non-deterministic State Machine
Eğer bir state'ten aynı girdi ile birden fazla state'e geçilebiliyorsa, bu örüntüye non-deterministic state machine adı verilir.

Karnaugh Map
Karnaugh Map yani K-Map state geçişlerinde belki işe yarayabilir.

IEEE 754 - Float

Giriş
Float'un bir diğer ismi ise Single-precision floating-point format. Bu isimdeki single kelimesini gördükten sonra double tipinin niçin böyle isimlendirildiğini anlamak daha kolay.

Float 32 bitlik yer kullanırken double 64 bitlik (iki katı) yer kullanıyor. Bu yüzden ismi double olarak geçiyor.

Float Niçin Halen Var?
Double tipi float tipinin yaptığı her şeyi yapıyor. Öyleyse niçin float halen var. Sebepleri şöyle olabilir.
1. float daha az bellek harcar. Gömülü ortamlarda bu önemli olabilir.
2. GPU'da float işlemleri double işlemlerine göre çok daha hızlı. Oyun kodlarında bu önemli olabilir.

Precision
Not : Bir çok yazıda precision yerine "significant figure" kelimesi de kullanılıyor. Ben bu yazıda precision kelimesini kullandım, çünkü float yapısı içindeki significant kavramı ile karışmasın istedim.

Precision toplam hane sayısı anlamına gelir. Bu veri tipi ile toplam 7 hane büyüklüğüne (precision) kadar sayıları saklamak mümkün. Yani şöyle bir sayıyı saklayabiliriz.
3.141592 - Toplam 7 hane
Ya da şöyle
float: 0.3333333 - Toplam 7 hane, sıfır hariç
Not : Bir çok yazıda precision yerine "significant figure" kelimesi de kullanılıyor. Ben bu yazıda precision kelimesini kullandım, çünkü float yapısı içindeki significant kavramı ile karışmasın istedim.

En Küçük Sayı
C Dili
Açıklaması şöyle
FLT_MIN (normalized minimal positive value) = 1.175494351e-38F
FLT_TRUE_MIN (denormalized minimal positive value) = 1.401298464e-45F
FLT_TRUE şöyle hesaplanır.
float float_min()
{
  int exp_bit = CHAR_BIT * sizeof(float) - FLT_MANT_DIG;
  float exp = 2 - pow(2, exp_bit - 1);

  float m = pow(2, -(FLT_MANT_DIG - 1));

  return m * pow(2, exp);
}

int main()
{
    printf("%g\n", float_min());
}
Java Dili
Açıklaması şöyle
Even if the name is misleading, Float.MIN_VALUE is a positive value, higher than 0:
...
The real minimum float value is, in fact: -Float.MAX_VALUE.
Decimal Precision
Kaç tane ondalık hane saklanabileceği anlamına gelir. Bu veri tipi ile noktanın sol tarafında en fazla 6 tam sayı hanesi tutulabilir. Yani tüm 7 haneli tam sayılar float'a çevrilip tekrar tam sayıya çevrilemezler. Bazıları kaybolur. Ama tüm 6 haneli tam sayılar float'a çevrilip tekrar tam sayı haline gelebilir.
cout << numeric_limits<float>::digits10 <<endl;//6 verir
Yapısı
Float için kullanılan 32 bit aşağıdaki gibi bölümleniyor

   1 bit|7bit    |23 bit
    sign|exponent|mantissa veya significant
Yatay olarak bakarsak şöyle
sign : 1 bit
exponent : 8 bits
fraction : 23 bits
Türkçeleri şöyle: Sign = Yön, Exponent = Üst, Mantissa = Kök

Sign
Sayının artı veya eksi olduğunu belirtir. 1 ise eksi sayıdır.

Exponent
Exponent alanı 127'ye göre referans alınır. Örneğin exponent olarak 1 elde etmek istiyorsak 7 bitlik bu alana 128 yazmak gerekiyor çünkü 128- 127 = 1 .

Eğer exponent 255 ise, sayı infinity veya NaN'dır. Mantissa'ya göre karar verilir
If the exponent field is 255 then the number is infinity (if the mantissa is zero) or a NaN (if the mantissa is non-zero)
Eğer exponent 1- 254 arasında ise, normalized sayıdır ve şöyle hesaplanır
(1.0 + mantissa-field / 0x800000) * 2^(exponent-field-127)
Eğer exponent 0 ise, denormalized sayıdır ve şöyle hesaplanır
(mantissa-field / 0x800000) * 2^-126

Mantissa
Float veri tipinin mantissa alanı sadece 23 bit büyüklüğünde. Mantissa'nın solunda her zaman gizli 1 biti olduğu kabul edilir. Bu durumda 2^24'ten büyük (16,777,216) yani 16 milyondan biraz büyük tam sayıları float'a atamak hataya sebep oluyor. Mümkünse float yerine her zaman double kullanılmalı.

Buradaki açıklamada da mantissa'dan daha büyük bir int değer, float'a atandıktan sonra karşılaşılan bir hata açıklanmış

Alanlara erişmek
Şöyle yaparız.
float x = ...;
// split the given bits of sign exponent and fraction

unsigned int sign = (x & 0x80000000) >> 31;
unsigned int expo = (x & 0x7F800000) >> 23;
unsigned int frac = (x & 0x007fffff);
"Section 7.4 Beej's Guide to Network Programming" sayfasında IEEE 754 kullanmayan platformlarda, IEEE 754'e göre encoding işlemini yapmak için şöyle bir kod parçası var. Kod bazı durumları ele almadığı içi eksik, ancak mantığı göstermek için not aldım.
uint64_t pack754(long double f, unsigned bits, unsigned expbits)
{
  long long sign = ...;
  
  // calculate the binary form (non-float) of the significand data
  long long significand = ...;
  // get the biased exponent
  long long exp = ...
  // return the final answer
  return (sign<<(bits-1)) | (exp<<(bits-expbits-1)) | significand;
}

int main(void)
{
    float f = 3.1415926;
    uint32_t fi;

    printf("float f: %.7f\n", f);

    fi = pack754(f, 32, 8);
    printf("float encoded: 0x%08" PRIx32 "\n", fi);

    return 0;
}
Bellekte Temsili
Örnek
5.2 bellek şöyle temsil edilir.
0 10000001 01001100110011001100110    
S    E               M
S = 0 olduğu için pozitif bir sayıdır. Exponent = 129 ancak bias çıkarılınca 2 kalır. Yani 10^2'dir.
Mantissanın başında gizli bir 1 vardır.
Dolayısıyla
101... şeklinde düşünülürse zaten 5 gibi bir rakam elde edilir. Fraction şöyledir.
bits in M: 0   1    0     0      1       ... 
weight:    0.5 0.25 0.125 0.0625 0.03125 ... (take the half of the previous in each step)
Bu da toplayınca 0.1999998 gibi bir değer verir. Yani kabaca 5.2'yi elde ederiz.

Örnek
Elimizde 1864.78 sayısı olsun. Fraction kısmı bellekte şöyle temsil edilir.
number   : 1864.78
float    : 1864.780029  (actual nearest representation in memory)
integer  : 1864
fraction : 0.780029

 2 * 0.780029 = 1.560059  =>  integer part (1) fraction (0.560059)  =>  '1'
 2 * 0.560059 = 1.120117  =>  integer part (1) fraction (0.120117)  =>  '1'
 2 * 0.120117 = 0.240234  =>  integer part (0) fraction (0.240234)  =>  '0'
 2 * 0.240234 = 0.480469  =>  integer part (0) fraction (0.480469)  =>  '0'
 2 * 0.480469 = 0.960938  =>  integer part (0) fraction (0.960938)  =>  '0'
 2 * 0.960938 = 1.921875  =>  integer part (1) fraction (0.921875)  =>  '1'
 2 * 0.921875 = 1.843750  =>  integer part (1) fraction (0.843750)  =>  '1'
 2 * 0.843750 = 1.687500  =>  integer part (1) fraction (0.687500)  =>  '1'
 2 * 0.687500 = 1.375000  =>  integer part (1) fraction (0.375000)  =>  '1'
 2 * 0.375000 = 0.750000  =>  integer part (0) fraction (0.750000)  =>  '0'
 2 * 0.750000 = 1.500000  =>  integer part (1) fraction (0.500000)  =>  '1'
 2 * 0.500000 = 1.000000  =>  integer part (1) fraction (0.000000)  =>  '1'
Böylece şu değere erişiriz. 1864 ikili tabanda 11101001000 olarak tutulur.
decimal  : 11101001000
fraction : 110001111011
sign bit : 0
integer ve fraction toplam 10 haneden oluştuğu ve float 1.XXX şeklinde tutulduğu için exponent 10 olur. Bu değer normalize edersek şöyle bir sonuca varırız.
11101001000.110001111011  =>  1.1101001000110001111011

     exponent bias: 10
 unbiased exponent: 127
 __________________+____

   biased exponent: 137
   binary exponent: 10001001
Nihayet şöyle bir gösterime geliriz.
IEEE-754 Single Precision Floating Point Representation

  0 1 0 0 0 1 0 0 1 1 1 0 1 0 0 1 0 0 0 1 1 0 0 0 1 1 1 1 0 1 1 0
 |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
 |s|      exp     |                  mantissa                    |
İkilik Sayıdan 10'luk Sayıya Çevirmek
Not : IEEE 754 tek standart değildir. Geçmişte başka standartlar da kullanılmış. MIL-STD-1750A çevrim örneği için buraya bakabilirsiniz.

Kökün başına her zaman "1." sayısı getirilir. Exponent ve Yön ile çarpılır.

Örnek 1
0|10000000|11000000000000000000000 sign|exponent| mantissa

Mantissa'nın başına 1 getirdiğimiz ve ikilik taban kullandığımız için çevirmek istediğimiz sayı şudur
+(1.11)base 2 x 2^(128-127)
Daha sonra şu hale gelir.
1.11 sağdan başyarak yazılır. Önce ilk bit bir olduğu için 2^0, solundaki bit te bir olduğu için 2^-1, solundaki bir bir olduğu için 2^-2. Bu sayıların toplamı * exponent
(2^0 + 2^-1 + 2^-2) x 2^1